Compare commits
27 Commits
593f03648b
...
feature/na
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d6b4bf3b3 | |||
| 313ef43e9c | |||
| 058633742e | |||
| e1968e14b0 | |||
| 6b362d77f0 | |||
| 57c6d74ff5 | |||
| bed48b4cb4 | |||
| 05854c84d8 | |||
| 2c86e90b76 | |||
| e73ca6b532 | |||
| 7fea931b63 | |||
| 2ceab090fd | |||
| d522a44029 | |||
| 06b13853db | |||
| 6be0fbac7d | |||
| 062042b590 | |||
| 1ca77b6611 | |||
| 685badc59a | |||
| dacda3b3a6 | |||
| 40a44848a8 | |||
| 0b294a782c | |||
| 8beddba367 | |||
| 6ba32a7dfa | |||
| 36a70db69f | |||
| 8f91a10331 | |||
| 1db9ef0794 | |||
| ceeebfc964 |
File diff suppressed because one or more lines are too long
Binary file not shown.
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
@@ -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"]
|
||||
@@ -8,8 +8,10 @@
|
||||
import 'dart:io'; // flutter_ignore: dart_io_import.
|
||||
import 'package:path_provider_android/path_provider_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: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:path_provider_linux/path_provider_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) {
|
||||
try {
|
||||
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) {
|
||||
try {
|
||||
DeviceInfoPlusLinuxPlugin.registerWith();
|
||||
|
||||
@@ -61,6 +61,12 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/crypto-3.0.3",
|
||||
@@ -85,6 +91,12 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0",
|
||||
@@ -157,6 +169,12 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/flutter_box_transform-0.4.4",
|
||||
@@ -169,6 +187,12 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "../library/flutter_flow_chart",
|
||||
@@ -259,6 +283,18 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/latlong2-0.9.1",
|
||||
@@ -421,6 +457,18 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3",
|
||||
@@ -529,6 +577,24 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/table_calendar-3.1.2",
|
||||
@@ -547,6 +613,12 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/typed_data-1.3.2",
|
||||
@@ -601,6 +673,30 @@
|
||||
"packageUri": "lib/",
|
||||
"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",
|
||||
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/win32-5.5.0",
|
||||
@@ -638,7 +734,7 @@
|
||||
"languageVersion": "3.3"
|
||||
}
|
||||
],
|
||||
"generated": "2024-07-17T08:10:14.640895Z",
|
||||
"generated": "2024-08-07T09:57:10.081261Z",
|
||||
"generator": "pub",
|
||||
"generatorVersion": "3.3.4"
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ convert
|
||||
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/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
|
||||
2.19
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/crypto-3.0.3/
|
||||
@@ -54,6 +58,10 @@ dashed_path
|
||||
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/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
|
||||
2.12
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/
|
||||
@@ -98,6 +106,10 @@ fixnum
|
||||
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/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
|
||||
3.0
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_box_transform-0.4.4/
|
||||
@@ -106,6 +118,10 @@ flutter_colorpicker
|
||||
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/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
|
||||
3.1
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_lints-3.0.2/
|
||||
@@ -154,6 +170,14 @@ irondash_message_channel
|
||||
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/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
|
||||
3.0
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/latlong2-0.9.1/
|
||||
@@ -262,6 +286,14 @@ proj4dart
|
||||
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/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
|
||||
3.1
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/
|
||||
@@ -330,6 +362,18 @@ super_native_extensions
|
||||
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/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
|
||||
3.0
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/table_calendar-3.1.2/
|
||||
@@ -342,6 +386,10 @@ test_api
|
||||
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/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
|
||||
2.17
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/typed_data-1.3.2/
|
||||
@@ -378,6 +426,22 @@ web
|
||||
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/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
|
||||
3.3
|
||||
file:///home/mr/.pub-cache/hosted/pub.dev/win32-5.5.0/
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
desktop_window=/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/
|
||||
device_info_plus=/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/
|
||||
desktop_window=/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.1/
|
||||
device_info_plus=/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/
|
||||
irondash_engine_context=/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/
|
||||
path_provider=/home/mr/.pub-cache/hosted/pub.dev/path_provider-2.1.3/
|
||||
path_provider=/home/mr/.pub-cache/hosted/pub.dev/path_provider-2.1.4/
|
||||
path_provider_android=/home/mr/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/
|
||||
path_provider_foundation=/home/mr/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/
|
||||
path_provider_linux=/home/mr/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/
|
||||
path_provider_windows=/home/mr/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/
|
||||
path_provider_windows=/home/mr/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/
|
||||
shared_preferences=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/
|
||||
shared_preferences_android=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/
|
||||
shared_preferences_foundation=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/
|
||||
shared_preferences_linux=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/
|
||||
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/
|
||||
super_native_extensions=/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/
|
||||
shared_preferences_foundation=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/
|
||||
shared_preferences_linux=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/
|
||||
shared_preferences_web=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.1/
|
||||
shared_preferences_windows=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/
|
||||
super_native_extensions=/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/
|
||||
|
||||
File diff suppressed because one or more lines are too long
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
build/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
25
Dockerfile
25
Dockerfile
@@ -5,13 +5,17 @@ FROM debian:latest AS build-env
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl git unzip
|
||||
|
||||
ARG WORKSPACE_HOST="https://localhost:49618"
|
||||
ARG WORKFLOW_HOST="https://localhost:49618"
|
||||
ARG SEARCH_HOST="https://localhost:49618"
|
||||
ARG ITEM_HOST="https://localhost:49618"
|
||||
|
||||
ARG WORKSPACE_HOST="http://localhost:8089/oc"
|
||||
ARG WORKFLOW_HOST="http://localhost:8088/oc"
|
||||
ARG ITEM_HOST="http://localhost:8087/oc"
|
||||
ARG SCHEDULER_HOST="http://localhost:8090/oc"
|
||||
ARG LOGS_HOST="http://localhost:3100"
|
||||
ARG PEER_HOST="http://localhost:8093/oc"
|
||||
ARG DATACENTER_HOST="http://localhost:8092/oc"
|
||||
ARG COLLABORATIVE_AREA_HOST="http://localhost:8091/oc"
|
||||
ARG AUTH_MODE=true
|
||||
# define variables
|
||||
ARG FLUTTER_SDK=/usr/local/flutter
|
||||
ARG FLUTTER_SDK=/usr/local/flutter
|
||||
ARG FLUTTER_VERSION=3.19.6
|
||||
ARG APP=/app/
|
||||
|
||||
@@ -38,10 +42,15 @@ WORKDIR $APP
|
||||
RUN flutter clean
|
||||
RUN flutter pub get
|
||||
RUN flutter build web \
|
||||
--dart-define=AUTH_MODE=$AUTH_MODE \
|
||||
--dart-define=WORKSPACE_HOST=$WORKSPACE_HOST \
|
||||
--dart-define=WORKFLOW_HOST=$WORKFLOW_HOST \
|
||||
--dart-define=SEARCH_HOST=$SEARCH_HOST \
|
||||
--dart-define=ITEM_HOST=$ITEM_HOST
|
||||
--dart-define=PEER_HOST=$PEER_HOST \
|
||||
--dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST \
|
||||
--dart-define=SCHEDULER_HOST=$SCHEDULER_HOST \
|
||||
--dart-define=LOGS_HOST=$LOGS_HOST \
|
||||
--dart-define=ITEM_HOST=$ITEM_HOST \
|
||||
--dart-define=DATACENTER_HOST=$DATACENTER_HOST
|
||||
# once heare the app will be compiled and ready to deploy
|
||||
|
||||
# use nginx to deploy
|
||||
|
||||
@@ -43,4 +43,7 @@ At the root of the project :
|
||||
- `docker build . -t oc-front`
|
||||
if localisation services change : `docker build -t oc-front --build-arg WORKSPACE_HOST=<SERVICE URL> --build-arg WORKFLOW_HOST=<SERVICE URL> --build-arg SEARCH_HOST=<SERVICE URL> --build-arg ITEM_HOST=<SERVICE URL> .`
|
||||
|
||||
- `docker-compose up -d --build --force-recreate`
|
||||
- `docker-compose up -d --build --force-recreate`
|
||||
|
||||
## HELP
|
||||
sudo apt install libwebkit2gtk-4.0-dev
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
|
||||
|
||||
@@ -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.
BIN
build/flutter_assets/packages/timezone/data/latest_all.tzf
Normal file
BIN
build/flutter_assets/packages/timezone/data/latest_all.tzf
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,65 +1,123 @@
|
||||
# ninja log v5
|
||||
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h df34b103123784f1
|
||||
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1
|
||||
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1
|
||||
4 320 1721230626649119048 plugins/super_native_extensions/_phony_ 74762aee97d0d662
|
||||
5895 6038 1720171596542283915 plugins/desktop_window/libdesktop_window_plugin.so 26c8f2b838605d38
|
||||
3 5644 0 flutter/_phony_ df34b103123784f1
|
||||
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1
|
||||
3 5644 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_engine.h df34b103123784f1
|
||||
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.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
|
||||
43 7102 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_method_codec.h df34b103123784f1
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1
|
||||
43 7102 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/fl_dart_project.h df34b103123784f1
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1
|
||||
19318 20273 0 CMakeFiles/install.util 558f353ee1373233
|
||||
43 412 1723042867477311806 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
|
||||
18891 19318 1723042886400968232 intermediates_do_not_run/oc_front 4e630cc1de7b670a
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h df34b103123784f1
|
||||
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
|
||||
5645 5781 1721230632125036886 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022
|
||||
3 326 1721231108669887541 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
|
||||
3 326 1721231108669887541 plugins/super_native_extensions/_phony_ 74762aee97d0d662
|
||||
3 5916 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_basic_message_channel.h df34b103123784f1
|
||||
3 5916 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_binary_messenger.h df34b103123784f1
|
||||
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h df34b103123784f1
|
||||
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h df34b103123784f1
|
||||
3 5916 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_json_method_codec.h df34b103123784f1
|
||||
3 5916 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_method_call.h df34b103123784f1
|
||||
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h df34b103123784f1
|
||||
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h df34b103123784f1
|
||||
3 5916 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_plugin_registrar.h df34b103123784f1
|
||||
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1
|
||||
3 5916 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_standard_method_codec.h df34b103123784f1
|
||||
3 5916 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_value.h df34b103123784f1
|
||||
3 5916 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/flutter_linux.h df34b103123784f1
|
||||
3 5916 0 flutter/_phony_ df34b103123784f1
|
||||
5919 6044 1721231114401801556 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022
|
||||
5918 6335 1721231114689797236 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4
|
||||
5917 6380 1721231114733796575 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769
|
||||
6380 6517 1721231114873794475 intermediates_do_not_run/oc_front 4e630cc1de7b670a
|
||||
6517 6648 0 CMakeFiles/install.util 558f353ee1373233
|
||||
43 7102 0 flutter/_phony_ df34b103123784f1
|
||||
13608 16421 1720171474184250688 plugins/desktop_window/CMakeFiles/desktop_window_plugin.dir/desktop_window_plugin.cc.o 259dba9caad978aa
|
||||
43 7102 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_call.h df34b103123784f1
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h df34b103123784f1
|
||||
6105 7479 1720190159919162468 plugins/irondash_engine_context/CMakeFiles/irondash_engine_context_plugin.dir/irondash_engine_context_plugin.cc.o 439d26d301366f5a
|
||||
43 7102 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/libflutter_linux_gtk.so df34b103123784f1
|
||||
43 7102 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/flutter_linux.h df34b103123784f1
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1
|
||||
5895 6038 1720171596542283915 plugins/desktop_window/libdesktop_window_plugin.so 26c8f2b838605d38
|
||||
43 412 1723042867477311806 plugins/super_native_extensions/_phony_ 74762aee97d0d662
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h df34b103123784f1
|
||||
43 7102 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
|
||||
7117 18885 1723042885952976327 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h df34b103123784f1
|
||||
7117 16523 1723042883325023855 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h df34b103123784f1
|
||||
43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h df34b103123784f1
|
||||
7221 7661 1720190160103160034 CMakeFiles/oc_front.dir/main.cc.o b1d36a8b3fb9d7f7
|
||||
7116 18891 1723042885956976255 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769
|
||||
58 466 1723042916288432161 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
|
||||
58 466 1723042916288432161 plugins/super_native_extensions/_phony_ 74762aee97d0d662
|
||||
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so df34b103123784f1
|
||||
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1
|
||||
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h df34b103123784f1
|
||||
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1
|
||||
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
|
||||
|
||||
@@ -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.
@@ -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/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/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/FontManifest.json
|
||||
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/AssetManifest.bin
|
||||
@@ -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 }) {
|
||||
}
|
||||
}
|
||||
77
lib/core/models/shared_workspace_local.dart
Normal file
77
lib/core/models/shared_workspace_local.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/sections/end_drawer.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/shared_service.dart';
|
||||
import 'package:oc_front/models/shared.dart';
|
||||
import 'package:oc_front/models/workspace.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 CollaborativeAreaLocal {
|
||||
static String? current;
|
||||
static Map<String, CollaborativeArea> workspaces = {};
|
||||
static final SharedService _service = SharedService();
|
||||
|
||||
static Future<void> init(BuildContext context, bool changeCurrent) async {
|
||||
await _service.all(context).then((value) {
|
||||
if (value.data != null && value.data!.values.isNotEmpty ) {
|
||||
var vals = value.data!.values;
|
||||
for (var element in vals) {
|
||||
var ws = CollaborativeArea().deserialize(element);
|
||||
if (ws.id == null) { continue; }
|
||||
workspaces[ws.id!] = ws;
|
||||
}
|
||||
}
|
||||
}).catchError((e) => print(e));
|
||||
}
|
||||
|
||||
static CollaborativeArea? getCollaborativeArea(String id) {
|
||||
return workspaces[id];
|
||||
}
|
||||
|
||||
static Future<void> deleteCollaborativeArea(String id) async {
|
||||
if (workspaces.containsKey(id) && workspaces.length == 1) { return; }
|
||||
workspaces.remove(id);
|
||||
await _service.delete(null, id, {});
|
||||
}
|
||||
|
||||
static Future<void> createCollaborativeArea(BuildContext context, String name) async {
|
||||
Workspace n = Workspace(name: name);
|
||||
await _service.post(context, n.serialize(), {}).then((value) {
|
||||
if (value.data != null) {
|
||||
workspaces[value.data!.id!] = value.data!;
|
||||
endDrawerKey.currentState?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
CatalogItemFactory.key.currentState?.setState(() {});
|
||||
WorkflowFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void changeWorkspaceByName(String name) {
|
||||
var id = workspaces.entries.firstWhere((element) => element.value.name == "${name}_workspace").key;
|
||||
changeWorkspace(id);
|
||||
}
|
||||
|
||||
static void changeWorkspace(String id) {
|
||||
_service.put(null, id, { "active" : true }, {});
|
||||
endDrawerKey.currentState?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
CatalogItemFactory.key.currentState?.setState(() {});
|
||||
WorkflowFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
|
||||
static List<WorkSpaceItem> getCollaborativeAreasIDS() {
|
||||
List<WorkSpaceItem> res = [];
|
||||
for (var element in workspaces.entries) {
|
||||
res.add(WorkSpaceItem(id: element.key, name: element.value.name));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,227 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/core/sections/end_drawer.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/data.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
import 'package:oc_front/models/resources/workflow.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/workspace.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/item_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workspace_service.dart';
|
||||
import 'package:oc_front/pages/catalog.dart';
|
||||
import 'package:oc_front/pages/catalog_item.dart';
|
||||
import 'package:oc_front/pages/workflow.dart';
|
||||
|
||||
class WorkSpaceItem {
|
||||
String? id;
|
||||
String? name;
|
||||
WorkSpaceItem({this.id, this.name});
|
||||
}
|
||||
|
||||
class WorkspaceLocal {
|
||||
static Workspace? workspace;
|
||||
static String? current;
|
||||
static Map<String, Workspace> workspaces = {};
|
||||
static final WorkspaceService _service = WorkspaceService();
|
||||
static List<AbstractItem> items = [];
|
||||
static void init(BuildContext context) {
|
||||
_service.all(context).then((value) {
|
||||
workspace = value.data;
|
||||
if (workspace != null) {
|
||||
if (workspace!.data.isNotEmpty) {
|
||||
ItemService<DataItem, DataItem> dataService = ItemService<DataItem, DataItem>();
|
||||
for (var element in workspace!.data) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
dataService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> init(BuildContext? context, bool changeCurrent) async {
|
||||
var value = await _service.all(context);
|
||||
if (value.data != null && value.data!.values.isNotEmpty ) {
|
||||
var vals = value.data!.values;
|
||||
for (var element in vals) {
|
||||
var ws = Workspace().deserialize(element);
|
||||
if (ws.id == null) { continue; }
|
||||
workspaces[ws.id!] = ws;
|
||||
if (current == null) {
|
||||
current ??= ws.id;
|
||||
workspaces[current!] = ws;
|
||||
_service.put(context, ws.id!, { "active" : true }, {});
|
||||
}
|
||||
if (workspace!.computing.isNotEmpty) {
|
||||
ItemService<ComputingItem, ComputingItem> computingService = ItemService<ComputingItem, ComputingItem>();
|
||||
for (var element in workspace!.computing) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
computingService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (workspace!.datacenter.isNotEmpty) {
|
||||
ItemService<DataCenterItem, DataCenterItem> dataCenterService = ItemService<DataCenterItem, DataCenterItem>();
|
||||
for (var element in workspace!.datacenter) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
dataCenterService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (workspace!.storage.isNotEmpty) {
|
||||
ItemService<StorageItem, StorageItem> storageService = ItemService<StorageItem, StorageItem>();
|
||||
for (var element in workspace!.storage) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
storageService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
}
|
||||
if (ws.active == true && changeCurrent) {
|
||||
current = ws.id;
|
||||
}
|
||||
fill();
|
||||
HeaderConstants.headerKey.currentState?.setState(() {});
|
||||
}
|
||||
} else {
|
||||
await WorkspaceLocal.createWorkspace("default workspace", null);
|
||||
}
|
||||
}
|
||||
|
||||
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]!.computes) {
|
||||
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 bool hasWorkspace(String workspaceName) {
|
||||
for (var element in workspaces.values) {
|
||||
if (element.name == workspaceName) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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(null, 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(() {});
|
||||
HeaderConstants.headerKey.currentState?.setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
static List<AbstractItem> byTopic(String topic) {
|
||||
|
||||
static void changeWorkspaceByName(String name) {
|
||||
try {
|
||||
var id = workspaces.entries.firstWhere((element) => element.value.name == "${name}_workspace").key;
|
||||
changeWorkspace(id);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
static void changeWorkspace(String id) {
|
||||
_service.put(null, id, { "active" : true }, {});
|
||||
current = id;
|
||||
fill();
|
||||
HeaderConstants.headerKey.currentState?.setState(() {});
|
||||
endDrawerKey.currentState?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
CatalogItemFactory.key.currentState?.setState(() {});
|
||||
WorkflowFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
|
||||
static String getWorkspaceName(String id) {
|
||||
return workspaces[id]?.name ?? "";
|
||||
}
|
||||
|
||||
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<Shallow> getWorkspacesShallow() {
|
||||
List<Shallow> res = [];
|
||||
for (var element in workspaces.values) {
|
||||
res.add(Shallow(id: element.id ?? "", name: element.name ?? ""));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static List<AbstractItem> byWorkspace(String id) {
|
||||
List<AbstractItem> d = [];
|
||||
var w = workspaces[id]!;
|
||||
d = [ ...d, ...w.datas.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.computes.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;
|
||||
}
|
||||
|
||||
static List<AbstractItem> byTopic(String topic, bool all) {
|
||||
if (all) {
|
||||
List<AbstractItem> d = [];
|
||||
for (var w in workspaces.values) {
|
||||
d = [ ...d, ...w.datas.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.computes.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.processings.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.storages.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.workflows.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
}
|
||||
return d.where((element) => element.topic.toString() == topic).toList();
|
||||
}
|
||||
return WorkspaceLocal.items.where((element) => element.topic.toString() == topic).toList();
|
||||
}
|
||||
|
||||
static AbstractItem? getItem(String id) {
|
||||
static AbstractItem? getItem(String id, bool all) {
|
||||
if (all) {
|
||||
List<AbstractItem> 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.computes.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.processings.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.storages.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.workflows.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
}
|
||||
return d.isEmpty ? null : d.first;
|
||||
}
|
||||
var found = WorkspaceLocal.items.where((element) => element.id.toString() == id);
|
||||
return found.isEmpty ? null : found.first;
|
||||
}
|
||||
|
||||
static void addItem(AbstractItem item) {
|
||||
if (!WorkspaceLocal.hasItem(item)) {
|
||||
if (!WorkspaceLocal.hasItem(item) && workspaces[current] != null && workspaces[current]!.id != null) {
|
||||
items.add(item);
|
||||
try {
|
||||
_service.post(null, {}, { "id" : item.id.toString(), "rtype" : item.type.toString() });
|
||||
} catch (e) { /* */ }
|
||||
if (item.topic == "data") { workspaces[current]!.datas.add(item as DataItem); }
|
||||
if (item.topic == "processing") { workspaces[current]!.processings.add(item as ProcessingItem); }
|
||||
if (item.topic == "compute") { workspaces[current]!.computes.add(item as ComputeItem); }
|
||||
if (item.topic == "storage") { workspaces[current]!.storages.add(item as StorageItem); }
|
||||
if (item.topic == "workflow") { workspaces[current]!.workflows.add(item as WorkflowItem); }
|
||||
try {
|
||||
_service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {});
|
||||
} catch (e) {
|
||||
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
|
||||
}
|
||||
}
|
||||
}
|
||||
static void removeItem(AbstractItem item) {
|
||||
items = items.where((element) => element.name != item.name).toList();
|
||||
try { _service.delete(null, { "id" : item.id.toString(), "rtype" : item.type.toString() });
|
||||
} catch (e) { /* */ }
|
||||
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 == "compute") { workspaces[current]!.computes.removeWhere( (e) => e.id == item.id); }
|
||||
if (item.topic == "storage") { workspaces[current]!.storages.removeWhere( (e) => e.id == item.id); }
|
||||
if (item.topic == "workflow") { workspaces[current]!.workflows.removeWhere( (e) => e.id == item.id); }
|
||||
try {
|
||||
_service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {});
|
||||
} catch (e) {
|
||||
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
|
||||
}
|
||||
}
|
||||
static bool hasItemByID(String id) {
|
||||
return items.where((element) => element.id == id).isNotEmpty;
|
||||
}
|
||||
static bool hasItem(AbstractItem item) {
|
||||
return items.where((element) => element.name == item.name).isNotEmpty;
|
||||
return items.where((element) => element.id == item.id).isNotEmpty;
|
||||
}
|
||||
static void clear() => items.clear();
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/pages/catalog.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/widgets/items/item_row.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_text_input.dart';
|
||||
import 'package:oc_front/core/models/shared_workspace_local.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workspace_service.dart';
|
||||
|
||||
GlobalKey<EndDrawerWidgetState> endDrawerKey = GlobalKey<EndDrawerWidgetState>();
|
||||
class EndDrawerWidget extends StatefulWidget {
|
||||
@@ -14,35 +20,83 @@ class EndDrawerWidgetState extends State<EndDrawerWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
List<ItemRowWidget> itemRows = WorkspaceLocal.items.map(
|
||||
(e) => ItemRowWidget(contextWidth: 400, item: e, keys: [endDrawerKey, CatalogFactory.key],)).toList();
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
width: 400,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: SingleChildScrollView(
|
||||
return Stack( children: [
|
||||
Container(
|
||||
color: Colors.white,
|
||||
width: 400,
|
||||
height: getHeight(context),
|
||||
child: Column( children: [
|
||||
Container(
|
||||
width: 400,
|
||||
height: 50,
|
||||
decoration: const BoxDecoration(color: Color.fromRGBO(38, 166, 154, 1)),
|
||||
child: const Center(
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(padding: EdgeInsets.only(right: 20), child: Icon(Icons.shopping_cart_outlined, size: 18, color: Colors.white)),
|
||||
Text("Workspace", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.w600))
|
||||
])
|
||||
|
||||
Container(
|
||||
width: 400,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(color: lightColor ),
|
||||
child: const Center(
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(padding: EdgeInsets.only(right: 20), child: Icon(Icons.shopping_cart_outlined, size: 18, color: Colors.white)),
|
||||
Text("Workspace", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.w600))
|
||||
])
|
||||
|
||||
),
|
||||
),
|
||||
),
|
||||
itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 50,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Center(child: Text("WORKSPACE IS EMPTY",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white))))
|
||||
: Container( child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Column( children: itemRows)
|
||||
)),
|
||||
])
|
||||
)
|
||||
ShallowDropdownInputWidget(
|
||||
current: WorkspaceLocal.current,
|
||||
filled: Colors.white,
|
||||
width: 400,
|
||||
all: () async => WorkspaceLocal.getWorkspacesShallow(),
|
||||
canRemove: (p0) => p0 != null,
|
||||
remove: (p0) async {
|
||||
await WorkspaceService().delete(context, p0, {}).then( (e) => WorkspaceLocal.deleteWorkspace(p0));
|
||||
},
|
||||
type: CollaborativeAreaType.workspace,
|
||||
change: (String? change) {
|
||||
WorkspaceLocal.changeWorkspace(change.toString());
|
||||
}
|
||||
),
|
||||
Container(
|
||||
width: 400,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(bottom: BorderSide(color: midColor), top: BorderSide(color: midColor)),
|
||||
),
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Padding(padding: EdgeInsets.only(right: 5), child: Icon(Icons.share, size: 12, color: Colors.grey)),
|
||||
Text( (WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared) == null ?
|
||||
"actually not shared" : "share with ${CollaborativeAreaLocal.workspaces[WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared!]}",
|
||||
style: TextStyle( fontSize: 14, color: Colors.grey ),),
|
||||
]),
|
||||
),
|
||||
Column( children: [
|
||||
itemRows.isEmpty ? Container( height: getHeight(context) - 140,
|
||||
color: Colors.white,
|
||||
child: Center(child: Text("WORKSPACE IS EMPTY",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: midColor))))
|
||||
: Container( height: getHeight(context) - 140, child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column( children: [ ...itemRows, Container(height: 50)])
|
||||
)),
|
||||
])
|
||||
])
|
||||
),
|
||||
Positioned( bottom: 0, left: 0,
|
||||
child: Tooltip( message: "create workspace", child: ShallowTextInputWidget(
|
||||
width: 400,
|
||||
tooltipLoad: "create workspace",
|
||||
iconLoad: Icons.create_new_folder_sharp,
|
||||
type: CollaborativeAreaType.workspace,
|
||||
color: Colors.white,
|
||||
filled: midColor,
|
||||
hint: "enter workspace name",
|
||||
hintColor: Colors.grey,
|
||||
canLoad: (String? remove) => remove != null,
|
||||
load: (Map<String?, dynamic> add) async {
|
||||
if (add["name"] == null) { return; }
|
||||
WorkspaceLocal.createWorkspace(add["name"], context);
|
||||
},
|
||||
),
|
||||
))
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
49
lib/core/sections/header/default.dart
Normal file
49
lib/core/sections/header/default.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/perms_service.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_text_input.dart';
|
||||
|
||||
class DefaultWidget extends StatefulWidget{
|
||||
const DefaultWidget (): super(key: null);
|
||||
@override DefaultWidgetState createState() => DefaultWidgetState();
|
||||
}
|
||||
class DefaultWidgetState extends State<DefaultWidget> {
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: getMainWidth(context),
|
||||
height: getHeight(context) - 50,
|
||||
color: midColor,
|
||||
padding: EdgeInsets.only(top: 50),
|
||||
child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: getMainHeight(context) < 600 ? MainAxisAlignment.center : MainAxisAlignment.start,
|
||||
children: [ getMainHeight(context) < 600 ? Container() : Container(
|
||||
margin: EdgeInsets.only(left: 40),
|
||||
child: SvgPicture.asset("assets/images/logo.svg", width: 300, height: (getMainHeight(context) / (1.8) ), semanticsLabel: 'OpenCloud Logo')
|
||||
),
|
||||
ShallowTextInputWidget(
|
||||
alignment: MainAxisAlignment.center,
|
||||
width: getMainWidth(context) / 1.5,
|
||||
type: CollaborativeAreaType.workspace,
|
||||
hint: "search in resources...",
|
||||
iconLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? Icons.search : null,
|
||||
iconRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? Icons.screen_search_desktop_outlined : null,
|
||||
tooltipLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? "search" : null,
|
||||
tooltipRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? "distributed search" : null,
|
||||
canLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String? str) => str != null && str.isNotEmpty : null,
|
||||
canRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String? str) => str != null && str.isNotEmpty : null,
|
||||
change: (value) => SearchConstants.set(value),
|
||||
loadStr: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String val) async {
|
||||
AppRouter.currentRoute.factory.search(context, false);
|
||||
} : null,
|
||||
remove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String val) async {
|
||||
AppRouter.currentRoute.factory.search(context, true);
|
||||
} : null,
|
||||
)
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,140 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:localstorage/localstorage.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/core/sections/header/default.dart';
|
||||
import 'package:oc_front/core/sections/header/menu.dart';
|
||||
import 'package:oc_front/core/sections/header/search.dart';
|
||||
import 'package:oc_front/core/services/perms_service.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
import 'package:oc_front/widgets/menu_clipper/clipper_menu.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_text_input.dart';
|
||||
|
||||
class SearchConstants {
|
||||
static final Map<String, String?> _searchHost = {};
|
||||
static String? get() { return _searchHost[AppRouter.currentRoute.route]; }
|
||||
static void set(String? search) { _searchHost[AppRouter.currentRoute.route] = search; }
|
||||
static void remove() { _searchHost.remove(AppRouter.currentRoute.route); }
|
||||
static void clear() {
|
||||
localStorage.setItem("search", "");
|
||||
_searchHost.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderConstants {
|
||||
static GlobalKey<HeaderMenuWidgetState> headerKey = GlobalKey<HeaderMenuWidgetState>();
|
||||
static final List<RouterItem> noHeader = [
|
||||
AppRouter.scheduler,
|
||||
AppRouter.compute,
|
||||
AppRouter.shared,
|
||||
AppRouter.workflowItem,
|
||||
AppRouter.workflowIDItem,
|
||||
];
|
||||
static HeaderWidgetState? headerWidget;
|
||||
static double height = 200;
|
||||
static String? title;
|
||||
static String? description;
|
||||
|
||||
static getKey() {
|
||||
headerKey = GlobalKey<HeaderMenuWidgetState>();
|
||||
return headerKey;
|
||||
}
|
||||
|
||||
static setTitle(String? v) {
|
||||
title = v;
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
HeaderConstants.headerWidget?.setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
static setDescription(String? v) {
|
||||
description = v;
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
HeaderConstants.headerWidget?.setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
static bool isNoHeader(String route) {
|
||||
return noHeader.where((element) => element.route == route).isNotEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
GlobalKey<HeaderWidgetState> headerWidgetKey = GlobalKey<HeaderWidgetState>();
|
||||
class HeaderWidget extends StatefulWidget {
|
||||
HeaderWidget () : super(key: headerWidgetKey);
|
||||
const HeaderWidget () : super(key: null);
|
||||
@override HeaderWidgetState createState() => HeaderWidgetState();
|
||||
}
|
||||
class HeaderWidgetState extends State<HeaderWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
headerWidgetKey = GlobalKey<HeaderWidgetState>();
|
||||
headerMenuKey.currentState?.closeMenu();
|
||||
HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) ? 50 : 200;
|
||||
HeaderConstants.headerWidget = this;
|
||||
if (HeaderConstants.isNoHeader(AppRouter.currentRoute.route)) {
|
||||
return Container();
|
||||
}
|
||||
if (AppRouter.currentRoute.factory.searchFill()) {
|
||||
return DefaultWidget();
|
||||
}
|
||||
HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) || !AppRouter.currentRoute.factory.searchFill() ? 50 : 100;
|
||||
return Column( children: [
|
||||
const HeaderMenuWidget(),
|
||||
HeaderConstants.isNoHeader(AppRouter.currentRoute.route) ? Container() : SearchWidget()
|
||||
AppRouter.currentRoute.factory.searchFill() ? Container() : Container(
|
||||
height: 50, width: getMainWidth(context),
|
||||
decoration: BoxDecoration(
|
||||
color: midColor,
|
||||
border: Border(bottom: BorderSide(color: Colors.white, width: 1),)
|
||||
),
|
||||
child: Row(crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
InkWell( onTap: () {
|
||||
AppRouter.currentRoute.factory.back(context);
|
||||
},
|
||||
child:
|
||||
Container(width: 50, height: 50,
|
||||
color: Colors.black,
|
||||
child: Center(child: Icon(Icons.keyboard_backspace, color: Colors.white))
|
||||
),
|
||||
),
|
||||
ShallowTextInputWidget(
|
||||
filled: midColor,
|
||||
current: AppRouter.currentRoute.factory.getSearch(),
|
||||
width: getMainWidth(context) - 501,
|
||||
type: CollaborativeAreaType.workspace,
|
||||
hint: "search in resources...",
|
||||
iconLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? Icons.search : null,
|
||||
iconRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? Icons.screen_search_desktop_outlined : null,
|
||||
tooltipLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? "search" : null,
|
||||
tooltipRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? "distributed search" : null,
|
||||
canLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String? str) => str != null && str.isNotEmpty : null,
|
||||
canRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String? str) => str != null && str.isNotEmpty : null,
|
||||
change: (value) => SearchConstants.set(value),
|
||||
loadStr: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String val) async {
|
||||
AppRouter.currentRoute.factory.search(context, false);
|
||||
} : null,
|
||||
remove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String val) async {
|
||||
AppRouter.currentRoute.factory.search(context, true);
|
||||
} : null,
|
||||
),
|
||||
Container( padding: EdgeInsets.only(left: 50),
|
||||
decoration: BoxDecoration( border: Border( left: BorderSide( color: Colors.white ))),
|
||||
child: ShallowDropdownInputWidget(
|
||||
prefixIcon: Padding( padding: EdgeInsets.only(right: 10), child: Icon(Icons.shopping_cart, color: Colors.grey)),
|
||||
current: WorkspaceLocal.current,
|
||||
width: 350,
|
||||
all: () async => WorkspaceLocal.getWorkspacesShallow(),
|
||||
type: CollaborativeAreaType.workspace,
|
||||
change: (String? change) {
|
||||
WorkspaceLocal.changeWorkspace(change.toString());
|
||||
},
|
||||
canLoad: (p0) => true,
|
||||
load: (p0) async {
|
||||
scaffoldKey.currentState?.openEndDrawer();
|
||||
},
|
||||
tooltipLoad: "open workspace manager",
|
||||
iconLoad: Icons.remove_red_eye,
|
||||
color: Colors.black,
|
||||
filled: midColor,
|
||||
hintColor: Colors.grey,
|
||||
))
|
||||
])
|
||||
),
|
||||
],);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +1,61 @@
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/auth.service.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/widgets/menu_clipper/clipper_menu.dart';
|
||||
import 'package:oc_front/widgets/dialog/login.dart';
|
||||
import 'package:oc_front/pages/catalog.dart';
|
||||
|
||||
class HeaderMenuWidget extends StatefulWidget{
|
||||
const HeaderMenuWidget ({ super.key });
|
||||
HeaderMenuWidget (): super(key: HeaderConstants.getKey());
|
||||
@override HeaderMenuWidgetState createState() => HeaderMenuWidgetState();
|
||||
}
|
||||
class HeaderMenuWidgetState extends State<HeaderMenuWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
width: getWidth(context),
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(bottom: BorderSide(color: Colors.grey.shade300))
|
||||
color: Colors.white,
|
||||
border: Border(bottom: BorderSide(color: midColor))
|
||||
),
|
||||
child: Padding(padding: const EdgeInsets.only(top: 5, bottom: 5, left: 50, right: 50),
|
||||
child: Stack(children: [
|
||||
/*...(searchWidgetKey.currentState == null ? [Positioned( left: -20, top: -5,
|
||||
child: SvgPicture.asset("assets/images/icon.svg", height: 70, semanticsLabel: 'OpenCloud Logo'))] : []),*/
|
||||
Row(crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
child: Stack(children: [
|
||||
AppRouter.currentRoute.factory.searchFill() ? Container() : Positioned( top: 0, left: 30,
|
||||
child: InkWell( onTap: () {
|
||||
CatalogFactory.key.currentState?.widget.isSearch = true;
|
||||
CatalogFactory.key.currentState?.widget.items = [];
|
||||
AppRouter.zones.first.go(context, {});
|
||||
AppRouter.zones.first.factory.getKey().currentState?.setState(() {});
|
||||
HeaderConstants.headerKey.currentState?.setState(() {});
|
||||
},
|
||||
child: Wrap( alignment: WrapAlignment.center, children: [
|
||||
SvgPicture.asset("assets/images/icon.svg", width: 70, height: 70, semanticsLabel: 'OpenCloud Logo'),
|
||||
Container( height: 50, alignment: Alignment.centerLeft, margin: const EdgeInsets.only(left: 20),
|
||||
child: Text(AppRouter.currentRoute.label ?? "Where am I ?", style: TextStyle( color: Colors.grey)))
|
||||
]))),
|
||||
Padding( padding: const EdgeInsets.only(left: 50),
|
||||
child: Row(crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Tooltip( message: "workspace/cart", child: Padding(padding: const EdgeInsets.only(left: 10),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.shopping_cart_outlined),
|
||||
onPressed: () {
|
||||
headerMenuKey.currentState?.closeMenu();
|
||||
scaffoldKey.currentState?.openEndDrawer();
|
||||
},
|
||||
)
|
||||
Center(child: Text("hello \"${AuthService.getUsername() ?? ""}\"", style: const TextStyle(color: Colors.grey, fontSize: 15))),
|
||||
Padding(padding: const EdgeInsets.only(top: 5, bottom: 5, right: 50, left: 20),
|
||||
child: Row(crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Tooltip( message: "logout", child: Padding(padding: const EdgeInsets.only(left: 10),
|
||||
child: IconButton(
|
||||
icon: const Icon(FontAwesomeIcons.powerOff),
|
||||
onPressed: () async {
|
||||
await AuthService.logout();
|
||||
mainKey?.currentState?.setState(() {});
|
||||
},
|
||||
)
|
||||
)),
|
||||
Tooltip( message: "login", child: Padding(padding: const EdgeInsets.only(left: 10),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.login_outlined),
|
||||
onPressed: () { showDialog(context: context, builder: (context) => LoginWidget()); },
|
||||
)
|
||||
)),
|
||||
Tooltip( message: "navigation", child: Padding(padding: const EdgeInsets.only(left: 10),
|
||||
child: ClipperMenuWidget(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
iconColor: Colors.white,
|
||||
)
|
||||
))
|
||||
]
|
||||
)
|
||||
))
|
||||
])
|
||||
)
|
||||
)])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
|
||||
class SearchConstants {
|
||||
static final Map<String, String?> _searchHost = {};
|
||||
static String? get() { return _searchHost[AppRouter.currentRoute.route]; }
|
||||
static void set(String? search) { _searchHost[AppRouter.currentRoute.route] = search; }
|
||||
static void remove() { _searchHost.remove(AppRouter.currentRoute.route); }
|
||||
static void clear() { _searchHost.clear(); }
|
||||
}
|
||||
|
||||
GlobalKey<SearchWidgetState> searchWidgetKey = GlobalKey<SearchWidgetState>();
|
||||
class SearchWidget extends StatefulWidget {
|
||||
SearchWidget (): super(key: GlobalKey<SearchWidgetState>());
|
||||
@override SearchWidgetState createState() => SearchWidgetState();
|
||||
}
|
||||
class SearchWidgetState extends State<SearchWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
searchWidgetKey = widget.key as GlobalKey<SearchWidgetState>;
|
||||
List<Widget> widgets = [
|
||||
...(MediaQuery.of(context).size.width > 600 || AppRouter.currentRoute.factory.searchFill()
|
||||
? [InkWell(
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () => AppRouter.zones.first.go(context, {}),
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 20, left: AppRouter.currentRoute.factory.searchFill() ? 40 : 0),
|
||||
child: SvgPicture.asset(
|
||||
width: 300,
|
||||
height: AppRouter.currentRoute.factory.searchFill() ?
|
||||
((MediaQuery.of(context).size.height - 50) / 2) : 150,
|
||||
"assets/images/logo.svg",
|
||||
semanticsLabel: 'OpenCloud Logo'
|
||||
)
|
||||
)
|
||||
)] : []),
|
||||
AppRouter.currentRoute.description != null ?
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(AppRouter.currentRoute.description!, style: const TextStyle(
|
||||
color: Color.fromRGBO(38, 166, 154, 1),
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w600
|
||||
)),
|
||||
Row(children: [
|
||||
...(AppRouter.currentRoute.help == null || AppRouter.currentRoute.help!.isEmpty ? []
|
||||
: [ const Padding( padding: EdgeInsets.only(right: 10),
|
||||
child: Icon(Icons.help_outline, color: Colors.grey, size: 20)),
|
||||
Text(AppRouter.currentRoute.help ?? "", style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400
|
||||
)) ])
|
||||
],)
|
||||
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width - 300 - 100,
|
||||
height: 50,
|
||||
color: Colors.white,
|
||||
child: TextField(
|
||||
onChanged: (value) => SearchConstants.set(value),
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search in ${AppRouter.currentRoute.route}...",
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
hintStyle: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w300
|
||||
),
|
||||
border: InputBorder.none
|
||||
)
|
||||
)
|
||||
),
|
||||
Tooltip(
|
||||
message: 'search',
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
AppRouter.currentRoute.factory.search(context);
|
||||
},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
border: Border(right: BorderSide(color: Colors.white)),
|
||||
),
|
||||
child: const Icon(Icons.search, color: Colors.white)
|
||||
)
|
||||
)
|
||||
),
|
||||
Tooltip(
|
||||
message: 'distributed search',
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
AppRouter.currentRoute.factory.search(context);
|
||||
},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
color: Colors.black,
|
||||
child: const Icon(Icons.screen_search_desktop_outlined, color: Colors.white)
|
||||
)
|
||||
)
|
||||
)
|
||||
])
|
||||
];
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: AppRouter.currentRoute.factory.searchFill() ? (MediaQuery.of(context).size.height - 50) : 150,
|
||||
color: Colors.grey.shade300,
|
||||
child: AppRouter.currentRoute.factory.searchFill() ? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: widgets)
|
||||
: Row( mainAxisAlignment: MediaQuery.of(context).size.width < 600
|
||||
? MainAxisAlignment.center : MainAxisAlignment.start, children: widgets)
|
||||
);
|
||||
}
|
||||
}
|
||||
20
lib/core/sections/left_menu.dart
Normal file
20
lib/core/sections/left_menu.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
|
||||
class LeftMenuWidget extends StatefulWidget {
|
||||
const LeftMenuWidget({Key? key}): super(key: key);
|
||||
@override LeftMenuWidgetState createState() => LeftMenuWidgetState();
|
||||
}
|
||||
|
||||
class LeftMenuWidgetState extends State<LeftMenuWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
var routes = AppRouter.zones.where( (e) => e.label != null && e.icon != null).toList();
|
||||
List<Widget> widgets = routes.map( (e) => Opacity( opacity: AppRouter.currentRoute.route == e.route ? 1 : .5,
|
||||
child: Tooltip( message: e.label, child: SizedBox( width: 50, height: 50, child: InkWell(
|
||||
onTap: () { e.go(context, {}); },
|
||||
child: Center( child: Icon(e.icon, color:Colors.white) ),
|
||||
),
|
||||
)))).toList();
|
||||
return Column( children: widgets);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:alert_banner/exports.dart';
|
||||
import 'package:localstorage/localstorage.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/widgets/dialog/alert.dart';
|
||||
@@ -11,19 +12,18 @@ import 'package:oc_front/core/services/html.dart' if (kIsWeb) 'dart:html' as htt
|
||||
class APIService<T extends SerializerDeserializer> {
|
||||
static bool forceRequest = false;
|
||||
static Map<String, APIResponse<dynamic>> cache = <String, APIResponse<dynamic>>{};
|
||||
static String auth = "";
|
||||
Dio _dio = Dio(
|
||||
BaseOptions(
|
||||
baseUrl: const String.fromEnvironment('HOST', defaultValue: 'http://localhost:8080'), // you can keep this blank
|
||||
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
|
||||
headers: { 'Content-Type': 'application/json; charset=UTF-8', 'Access-Control-Allow-Origin': '*' },
|
||||
),
|
||||
)..interceptors.add(LogInterceptor( requestHeader: true, ),);
|
||||
)..interceptors.add(LogInterceptor( requestHeader: true, ));
|
||||
|
||||
APIService({ required String baseURL }) {
|
||||
APIService({ required String baseURL}) {
|
||||
_dio = Dio(
|
||||
BaseOptions(
|
||||
baseUrl: baseURL, // you can keep this blank
|
||||
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
|
||||
headers: { 'Content-Type': 'application/json; charset=UTF-8', 'Access-Control-Allow-Origin': '*' },
|
||||
),
|
||||
)..interceptors.add(LogInterceptor( requestHeader: true, ),);
|
||||
}
|
||||
@@ -51,7 +51,6 @@ class APIService<T extends SerializerDeserializer> {
|
||||
Future _mainDownload(String url, String method, bool isFilter, String? extend, String savePath, bool isWeb, BuildContext context) async {
|
||||
try {
|
||||
downloadProgressNotifier.value = 0;
|
||||
// dio.options.headers["authorization"] = auth;
|
||||
if (isWeb) {
|
||||
_dio.get("$url${extend ?? ""}").then((value) {
|
||||
var url = http.Url.createObjectUrlFromBlob(http.Blob([value.data]));
|
||||
@@ -74,40 +73,40 @@ class APIService<T extends SerializerDeserializer> {
|
||||
Future<APIResponse<T>> _main(String url, dynamic body, String method, String succeed, bool force,
|
||||
BuildContext? context, Options? options) async {
|
||||
var err = "";
|
||||
|
||||
if ((!force) && cache.containsKey(url) && cache[url] != null ) {
|
||||
return cache[url]! as APIResponse<T>;
|
||||
}
|
||||
try {
|
||||
_dio.options.headers["authorization"] = auth;
|
||||
var type = localStorage.getItem('tokenType') ?? "bearer";
|
||||
_dio.options.headers["Authorization"] = "${type[0].toUpperCase() + type.substring(1)} ${localStorage.getItem('accessToken') ?? ""}";
|
||||
_dio.interceptors.clear();
|
||||
var response = await _request(url, method, body, options);
|
||||
if (response.statusCode != null && response.statusCode! < 400) {
|
||||
if (method == "delete") { cache.remove(url); return APIResponse<T>(); }
|
||||
APIResponse<T> resp = APIResponse<T>().deserialize(response.data);
|
||||
if (resp.error == "") {
|
||||
if (method == "get") { cache[url]=resp; }
|
||||
if (context != null && succeed != "") {
|
||||
// ignore: use_build_context_synchronously
|
||||
showAlertBanner(context, () {}, InfoAlertBannerChild(text: succeed), // <-- Put any widget here you want!
|
||||
try {
|
||||
showAlertBanner(context, () {}, InfoAlertBannerChild(text: succeed), // <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
} catch (e) { /* */ }
|
||||
}
|
||||
try { return cache[url] as APIResponse<T>;
|
||||
} catch (e) { return APIResponse(); }
|
||||
return resp;
|
||||
}
|
||||
err = resp.error ?? "internal error";
|
||||
}
|
||||
if (response.statusCode == 401) { err = "not authorized"; }
|
||||
} else if (response.statusCode == 401) { err = "not authorized"; }
|
||||
} catch(e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
err = e.toString();
|
||||
if (!e.toString().contains("context")) {
|
||||
print(e);
|
||||
print(s);
|
||||
err = e.toString();
|
||||
}
|
||||
}
|
||||
//if (err.contains("token") && err.contains("expired")) { AuthService().unAuthenticate(); }
|
||||
if (context != null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
showAlertBanner( context, () {}, AlertAlertBannerChild(text: err),// <-- Put any widget here you want!
|
||||
try {
|
||||
showAlertBanner( context, () {}, AlertAlertBannerChild(text: err),// <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
} catch (e) { /* */ }
|
||||
}
|
||||
throw Exception(err);
|
||||
}
|
||||
@@ -116,7 +115,8 @@ class APIService<T extends SerializerDeserializer> {
|
||||
var err = "";
|
||||
if (url != "") {
|
||||
try {
|
||||
_dio.options.headers["authorization"] = auth;
|
||||
var type = localStorage.getItem('tokenType') ?? "bearer";
|
||||
_dio.options.headers["Authorization"] = "${type[0].toUpperCase() + type.substring(1)} ${localStorage.getItem('accessToken') ?? ""}";
|
||||
_dio.interceptors.clear();
|
||||
var response = await _request(url, method, body, null);
|
||||
if (response.statusCode != null && response.statusCode! < 400) {
|
||||
@@ -129,7 +129,6 @@ class APIService<T extends SerializerDeserializer> {
|
||||
} catch(e, s) { print(e); print(s);
|
||||
err = "${e.toString()} ${const String.fromEnvironment('HOST', defaultValue: 'http://localhost:8080')}"; }
|
||||
} else { err = "no url"; }
|
||||
// if (err.contains("token") && err.contains("expired")) { AuthService().unAuthenticate(); }
|
||||
throw Exception(err);
|
||||
}
|
||||
|
||||
|
||||
99
lib/core/services/auth.service.dart
Normal file
99
lib/core/services/auth.service.dart
Normal file
@@ -0,0 +1,99 @@
|
||||
|
||||
import 'package:localstorage/localstorage.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/perms_service.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
class AuthService {
|
||||
static var isAuth = const bool.fromEnvironment('AUTH_MODE', defaultValue: false);
|
||||
static final _clientID = const String.fromEnvironment('CLIENT_ID', defaultValue: 'test-client');
|
||||
static APIService<SimpleData> service = APIService(
|
||||
baseURL: const String.fromEnvironment('AUTH_HOST', defaultValue: 'http://localhost:8080/auth'),
|
||||
);
|
||||
static Future<void> init() async {
|
||||
if (!isAuth) {
|
||||
return;
|
||||
}
|
||||
PermsService.init(localStorage.getItem('accessToken') ?? "");
|
||||
bool ok = await introspect().catchError( (e) => false );
|
||||
if (ok) {
|
||||
var now = DateTime.now();
|
||||
var expires = DateTime.parse(localStorage.getItem('expiresIn') ?? DateTime.now().toIso8601String());
|
||||
var duration = expires.difference(now);
|
||||
refresh(localStorage.getItem('accessToken') ?? "", localStorage.getItem('username') ?? "", duration);
|
||||
} else {
|
||||
localStorage.setItem('accessToken', '');
|
||||
localStorage.setItem('username', '');
|
||||
localStorage.setItem('expiresIn', '');
|
||||
}
|
||||
}
|
||||
|
||||
static bool isConnected() {
|
||||
if (!isAuth) {
|
||||
return true;
|
||||
}
|
||||
return (localStorage.getItem('accessToken') ?? "") != ""
|
||||
&& localStorage.getItem('username') != "";
|
||||
}
|
||||
|
||||
static String? getUsername() {
|
||||
if (!isAuth) {
|
||||
return "no auth user";
|
||||
}
|
||||
return localStorage.getItem('username') ?? "unknown";
|
||||
}
|
||||
|
||||
static Future<void> login(String username, String password) async {
|
||||
var token = await service.post("/login?client_id=$_clientID", <String, dynamic> {
|
||||
"username": username,
|
||||
"password": password
|
||||
}, null);
|
||||
if (token.code == 200 && token.data != null) {
|
||||
localStorage.setItem('accessToken', token.data?.value['access_token']);
|
||||
localStorage.setItem('tokenType', token.data?.value['token_type']);
|
||||
localStorage.setItem('username', username);
|
||||
localStorage.setItem('expiresIn', DateTime.now().add(
|
||||
Duration(seconds: token.data?.value['expires_in'])).toIso8601String());
|
||||
mainKey?.currentState?.setState(() {});
|
||||
PermsService.init(token.data?.value['access_token']);
|
||||
refresh(token.data?.value['access_token'] ?? "", username, Duration(seconds: token.data?.value['expires_in']));
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> logout() async {
|
||||
var token = await service.delete("/logout?client_id=$_clientID", null);
|
||||
if (token.code == 200) {
|
||||
localStorage.setItem('accessToken', '');
|
||||
localStorage.setItem('username', '');
|
||||
localStorage.setItem('expiresIn', '');
|
||||
PermsService.clear();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> introspect() async {
|
||||
if (!isConnected()) {
|
||||
return false;
|
||||
}
|
||||
// ignore: invalid_return_type_for_catch_error
|
||||
var isIntrospected = await service.get("/introspect", true, null).catchError((e) => mainKey?.currentState?.setState(() {}));
|
||||
return isIntrospected.code == 200;
|
||||
}
|
||||
|
||||
static Future<void> refresh(String accessToken, String username, Duration duration) async {
|
||||
Future.delayed(duration, () {
|
||||
service.post("/refresh?client_id=$_clientID", <String, dynamic> {
|
||||
"access_token": accessToken,
|
||||
"username": username
|
||||
}, null).then((token) {
|
||||
if (token.code == 200 && token.data != null) {
|
||||
PermsService.init(token.data?.value['access_token']);
|
||||
localStorage.setItem('accessToken', token.data?.value['access_token']);
|
||||
localStorage.setItem('username', username);
|
||||
localStorage.setItem('expiresIn',
|
||||
DateTime.now().add(Duration(seconds: token.data?.value['expires_in']) - Duration(seconds: 10)).toIso8601String());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
49
lib/core/services/enum_service.dart
Normal file
49
lib/core/services/enum_service.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
|
||||
class EnumService {
|
||||
static final APIService<EnumData> _service = APIService<EnumData>(
|
||||
baseURL: const String.fromEnvironment('ITEM_HOST',
|
||||
defaultValue: 'http://localhost:8080/catalog')
|
||||
);
|
||||
static String subPath = "/enum/";
|
||||
static Map<String, Map<String,dynamic>> enums = {};
|
||||
|
||||
static int? get(String path, dynamic name) {
|
||||
var n = enums[path];
|
||||
if (n == null) {
|
||||
return null;
|
||||
}
|
||||
var names = "$name";
|
||||
for (var nn in n.keys) {
|
||||
if (n[nn] == names || nn == names) {
|
||||
return int.parse(nn);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void init() {
|
||||
_load("infrastructure");
|
||||
_load("storage/type");
|
||||
_load("storage/size");
|
||||
_load("resource/type");
|
||||
_load("booking/status");
|
||||
_load("status");
|
||||
_load("pricing/strategy/buy");
|
||||
_load("pricing/strategy/data");
|
||||
_load("pricing/strategy/time");
|
||||
_load("pricing/strategy/storage");
|
||||
_load("pricing/strategy/privilege/storage");
|
||||
_load("pricing/strategy/privilege");
|
||||
_load("pricing/refund/type");
|
||||
}
|
||||
|
||||
static void _load(String name) {
|
||||
_service.get("$subPath$name", false, null).then((response) {
|
||||
if (response.code == 200) {
|
||||
enums[name] = response.data!.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
99
lib/core/services/perms_service.dart
Normal file
99
lib/core/services/perms_service.dart
Normal file
@@ -0,0 +1,99 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:oc_front/main.dart';
|
||||
|
||||
enum Perms {
|
||||
SEARCH_INTERNAL,// ignore: constant_identifier_names
|
||||
SEARCH_EXTERNAL, // ignore: constant_identifier_names
|
||||
|
||||
WORKSPACE_SHARE,// ignore: constant_identifier_names
|
||||
WORKSPACE_UNSHARE,// ignore: constant_identifier_names
|
||||
|
||||
WORKFLOW_CREATE, // ignore: constant_identifier_names
|
||||
WORKFLOW_EDIT, // ignore: constant_identifier_names
|
||||
WORKFLOW_DELETE, // ignore: constant_identifier_names
|
||||
WORKFLOW_BOOKING, // ignore: constant_identifier_names
|
||||
WORKFLOW_SHARE, // ignore: constant_identifier_names
|
||||
WORKFLOW_UNSHARE, // ignore: constant_identifier_names
|
||||
|
||||
PEER_SHARE, // ignore: constant_identifier_names
|
||||
PEER_UNSHARE, // ignore: constant_identifier_names
|
||||
|
||||
COLLABORATIVE_AREA_CREATE, // ignore: constant_identifier_names
|
||||
COLLABORATIVE_AREA_EDIT, // ignore: constant_identifier_names
|
||||
COLLABORATIVE_AREA_DELETE, // ignore: constant_identifier_names
|
||||
}
|
||||
|
||||
Map<Perms, String> perms = {
|
||||
Perms.SEARCH_INTERNAL: 'GET__CATALOG_COMPUTE_SEARCH_SEARCH'.toUpperCase(),
|
||||
Perms.SEARCH_EXTERNAL: 'Search External'.toUpperCase(),
|
||||
Perms.WORKSPACE_SHARE: 'POST__SHARED_COLLABORATIVE_AREA_ID_WORKSPACE_ID2'.toUpperCase(),
|
||||
Perms.WORKFLOW_CREATE: 'POST__WORKFLOW_'.toUpperCase(),
|
||||
Perms.WORKFLOW_UNSHARE: 'DELETE__SHARED_COLLABORATIVE_AREA_ID_WORKFLOW_ID2'.toUpperCase(),
|
||||
Perms.PEER_SHARE: 'POST__SHARED_COLLABORATIVE_AREA_ID_PEER_ID2'.toUpperCase(),
|
||||
Perms.PEER_UNSHARE: 'DELETE__SHARED_COLLABORATIVE_AREA_ID_PEER_ID2'.toUpperCase(),
|
||||
Perms.COLLABORATIVE_AREA_CREATE: 'POST__SHARED_COLLABORATIVE_AREA_'.toUpperCase(),
|
||||
Perms.COLLABORATIVE_AREA_EDIT: 'PUT__SHARED_COLLABORATIVE_AREA_ID'.toUpperCase(),
|
||||
Perms.COLLABORATIVE_AREA_DELETE: 'DELETE__SHARED_COLLABORATIVE_AREA_ID'.toUpperCase(),
|
||||
Perms.WORKSPACE_UNSHARE: 'DELETE__SHARED_COLLABORATIVE_AREA_ID_WORKSPACE_ID2'.toUpperCase(),
|
||||
Perms.WORKFLOW_EDIT: 'PUT__WORKFLOW_ID'.toUpperCase(),
|
||||
Perms.WORKFLOW_DELETE: 'DELETE__WORKFLOW_ID'.toUpperCase(),
|
||||
Perms.WORKFLOW_BOOKING: 'POST__DATACENTER_BOOKING_'.toUpperCase(),
|
||||
Perms.WORKFLOW_SHARE: 'POST__SHARED_COLLABORATIVE_AREA_ID_WORKFLOW_ID2'.toUpperCase(),
|
||||
};
|
||||
|
||||
class PermsService {
|
||||
static final Map<Perms, bool> _perms = {
|
||||
Perms.SEARCH_INTERNAL: false,
|
||||
Perms.SEARCH_EXTERNAL: false,
|
||||
Perms.WORKSPACE_SHARE: false,
|
||||
Perms.WORKSPACE_UNSHARE: false,
|
||||
Perms.WORKFLOW_CREATE: false,
|
||||
Perms.WORKFLOW_EDIT: false,
|
||||
Perms.WORKFLOW_DELETE: false,
|
||||
Perms.WORKFLOW_BOOKING: false,
|
||||
Perms.WORKFLOW_SHARE: false,
|
||||
Perms.WORKFLOW_UNSHARE: false,
|
||||
Perms.PEER_SHARE: false,
|
||||
Perms.PEER_UNSHARE: false,
|
||||
Perms.COLLABORATIVE_AREA_CREATE: false,
|
||||
Perms.COLLABORATIVE_AREA_EDIT: false,
|
||||
Perms.COLLABORATIVE_AREA_DELETE: false,
|
||||
};
|
||||
static final PermsService _instance = PermsService._internal();
|
||||
factory PermsService() => _instance;
|
||||
PermsService._internal();
|
||||
/* should decode claims such as in oc-auth */
|
||||
static Future<void> init(String token ) async {
|
||||
var claims = token.split(".").last;
|
||||
var decoded = base64.decode(claims);
|
||||
String foo = utf8.decode(decoded);
|
||||
try {
|
||||
var what = json.decode(foo);
|
||||
what = what["session"]["access_token"] as Map<String, dynamic>;
|
||||
|
||||
for (var w in perms.keys) {
|
||||
if (what.keys.contains(perms[w])) {
|
||||
_perms[w] = true;
|
||||
} else {
|
||||
_perms[w] = false;
|
||||
}
|
||||
}
|
||||
mainKey?.currentState?.setState(() {});
|
||||
} catch (e) {/**/}
|
||||
}
|
||||
|
||||
static void clear() {
|
||||
_perms.forEach((key, value) {
|
||||
_perms[key] = false;
|
||||
});
|
||||
}
|
||||
static bool getPerm(Perms perm) {
|
||||
return _perms[perm] ?? false;
|
||||
}
|
||||
|
||||
static void setPerm(Perms perm, bool value) {
|
||||
_perms[perm] = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/pages/catalog.dart';
|
||||
@@ -5,6 +6,7 @@ import 'package:oc_front/pages/catalog_item.dart';
|
||||
import 'package:oc_front/pages/datacenter.dart';
|
||||
import 'package:oc_front/pages/map.dart';
|
||||
import 'package:oc_front/pages/scheduler.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/pages/workflow.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -42,25 +44,33 @@ class RouterItem {
|
||||
AppRouter.currentRoute = this;
|
||||
var newPath = "$path";
|
||||
for (var arg in args) { newPath = newPath.replaceAll(":$arg", params[arg] ?? ""); }
|
||||
Future.delayed( const Duration(seconds: 1), () {
|
||||
HeaderConstants.setTitle(null);
|
||||
HeaderConstants.setDescription(null);
|
||||
});
|
||||
context.go(newPath);
|
||||
}
|
||||
}
|
||||
|
||||
class AppRouter {
|
||||
static const String home = "catalog";
|
||||
static String home = "catalog";
|
||||
static final RouterItem workflowItem = RouterItem(icon: Icons.rebase_edit, label: "workflow manager", route: "workflow",
|
||||
description: "View to select & create new workflow.", help: "Workflow only access to your workspace datas. If a an element of your flow is missing, perhaps means it's missing in workspace.",
|
||||
factory: WorkflowFactory());
|
||||
static final RouterItem catalogItem = RouterItem(description: "", help: "", route: "catalog/:id", factory: CatalogItemFactory(), args: ["id"]);
|
||||
static final RouterItem workflowIDItem = RouterItem(description: "", help: "", route: "workflow/:id", factory: WorkflowFactory(), args: ["id"]);
|
||||
static final RouterItem catalogItem = RouterItem(label: "resource", description: "", help: "", route: "catalog/:id", factory: CatalogItemFactory(), args: ["id"]);
|
||||
static final RouterItem catalog= RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: "catalog", factory: CatalogFactory());
|
||||
static final RouterItem scheduler = RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory());
|
||||
static final RouterItem compute = RouterItem(icon: Icons.dns_outlined, label: "my compute", route: "compute", factory: DatacenterFactory());
|
||||
static final RouterItem shared = RouterItem(icon: Icons.share_rounded, label: "collaborative area", route: "shared", factory: SharedFactory());
|
||||
|
||||
static List<RouterItem> zones = [
|
||||
RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory()),
|
||||
catalog,
|
||||
workflowItem,
|
||||
RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()),
|
||||
RouterItem(icon: Icons.dns_outlined, label: "my datacenter", route: "datacenter",
|
||||
description: "Manage & monitor your datacenter.", help: "not implemented for now",
|
||||
factory: DatacenterFactory()),
|
||||
scheduler,
|
||||
compute,
|
||||
RouterItem(icon: Icons.public_outlined, label: "localisations", route: "map", factory: MapFactory()),
|
||||
shared,
|
||||
workflowIDItem,
|
||||
catalogItem,
|
||||
];
|
||||
static List<String> history = [];
|
||||
|
||||
@@ -6,10 +6,22 @@ import 'package:oc_front/core/services/api_service.dart';
|
||||
abstract class AbstractService<T extends SerializerDeserializer> {
|
||||
abstract APIService<T> service;
|
||||
abstract String subPath;
|
||||
|
||||
Future<APIResponse<T>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) { throw UnimplementedError(); }
|
||||
Future<APIResponse<RawData>> all(BuildContext? context) {
|
||||
return service.raw(subPath, null, "get");
|
||||
}
|
||||
Future<APIResponse<T>> get(BuildContext? context, String id) {
|
||||
return service.get("$subPath$id", true, context);
|
||||
}
|
||||
Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return service.post(subPath, body, context);
|
||||
}
|
||||
Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return service.put("$subPath$id", body, context);
|
||||
}
|
||||
Future<APIResponse<T>> delete(BuildContext? context, String id, Map<String, String> params) {
|
||||
return service.delete("$subPath$id", context);
|
||||
}
|
||||
}
|
||||
|
||||
Future<APIResponse<T>> all(BuildContext? context) { throw UnimplementedError(); }
|
||||
Future<APIResponse<T>> get(BuildContext? context, String id);
|
||||
Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params);
|
||||
Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
Future<APIResponse<T>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
|
||||
}
|
||||
23
lib/core/services/specialized_services/booking_service.dart
Normal file
23
lib/core/services/specialized_services/booking_service.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
|
||||
class BookingExecutionService extends AbstractService<WorkflowExecution> {
|
||||
@override APIService<WorkflowExecution> service = APIService<WorkflowExecution>(
|
||||
baseURL: const String.fromEnvironment('DATACENTER_HOST', defaultValue: 'http://localhost:8080/datacenter')
|
||||
);
|
||||
@override String subPath = "/booking/";
|
||||
|
||||
@override Future<APIResponse<WorkflowExecution>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
return service.get("${subPath}search/${words.join("/")}", false, context);
|
||||
}
|
||||
|
||||
@override Future<APIResponse<WorkflowExecution>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<WorkflowExecution>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
36
lib/core/services/specialized_services/check_service.dart
Normal file
36
lib/core/services/specialized_services/check_service.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/widgets.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 CheckService extends AbstractService<Check> {
|
||||
@override APIService<Check> service = APIService<Check>(
|
||||
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8080/workflow')
|
||||
);
|
||||
@override String subPath = "/check/";
|
||||
|
||||
Future<APIResponse<Check>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
return service.get("$subPath${words.join("/")}", true, context);
|
||||
}
|
||||
@override
|
||||
Future<APIResponse<RawData>> all(BuildContext? context) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override
|
||||
Future<APIResponse<Check>> get(BuildContext? context, String id) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override
|
||||
Future<APIResponse<Check>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override
|
||||
Future<APIResponse<Check>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override
|
||||
Future<APIResponse<Check>> delete(BuildContext? context, String id, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
|
||||
class DatacenterService extends AbstractService<Resource> {
|
||||
@override APIService<Resource> service = APIService<Resource>(
|
||||
baseURL: const String.fromEnvironment('DATACENTER_HOST', defaultValue: 'http://localhost:8080/datacenter')
|
||||
);
|
||||
@override String subPath = "/";
|
||||
|
||||
@override Future<APIResponse<Resource>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override Future<APIResponse<Resource>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<Resource>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,24 +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/abstract.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
|
||||
class ItemService<S extends AbstractItem, T extends SerializerDeserializer<S>> extends AbstractService<T> {
|
||||
@override APIService<T> service = APIService<T>(
|
||||
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:49618')
|
||||
);
|
||||
@override String subPath = "/v1/${getTopic(S)}";
|
||||
|
||||
@override Future<APIResponse<T>> all(BuildContext? context) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<T>> get(BuildContext? context, String id) {
|
||||
if (id.contains(",")) { return service.get("$subPath/multi/$id", true, context); }
|
||||
return service.get("$subPath/$id", true, context);
|
||||
}
|
||||
@override Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return service.post("$subPath/", body, context);
|
||||
}
|
||||
@override Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<T>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
|
||||
}
|
||||
34
lib/core/services/specialized_services/logs_service.dart
Normal file
34
lib/core/services/specialized_services/logs_service.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/logs.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
|
||||
class LogsService extends AbstractService<LogsResult> {
|
||||
@override APIService<LogsResult> service = APIService<LogsResult>(
|
||||
baseURL: const String.fromEnvironment('LOGS_HOST', defaultValue: 'http://localhost:3100')
|
||||
);
|
||||
@override String subPath = "/loki/api/v1/";
|
||||
|
||||
@override Future<APIResponse<LogsResult>> 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"].toString().substring(0, 10)}&end=${params["end"].toString().substring(0, 10)}", false, context);
|
||||
}
|
||||
|
||||
@override Future<APIResponse<LogsResult>> get(BuildContext? context, String id) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<LogsResult>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<LogsResult>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<LogsResult>> delete(BuildContext? context, String id, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
10
lib/core/services/specialized_services/peer_service.dart
Normal file
10
lib/core/services/specialized_services/peer_service.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
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/shared.dart';
|
||||
|
||||
class PeerService extends AbstractService<Peer> {
|
||||
@override APIService<Peer> service = APIService<Peer>(
|
||||
baseURL: const String.fromEnvironment('PEER_HOST', defaultValue: 'http://localhost:8080/peer')
|
||||
);
|
||||
@override String subPath = "/";
|
||||
}
|
||||
23
lib/core/services/specialized_services/resource_service.dart
Normal file
23
lib/core/services/specialized_services/resource_service.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
|
||||
class ResourceService extends AbstractService<Resource> {
|
||||
@override APIService<Resource> service = APIService<Resource>(
|
||||
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:8080/catalog')
|
||||
);
|
||||
@override String subPath = "/resource/";
|
||||
|
||||
@override Future<APIResponse<Resource>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
return service.get("${subPath}search/${words.join("/")}", false, context);
|
||||
}
|
||||
|
||||
@override Future<APIResponse<Resource>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<Resource>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
|
||||
class SearchService extends AbstractService<Search> {
|
||||
@override APIService<Search> service = APIService<Search>(
|
||||
baseURL: const String.fromEnvironment('SEARCH_HOST', defaultValue: 'http://localhost:49618')
|
||||
);
|
||||
@override String subPath = "/v1/search";
|
||||
@override Future<APIResponse<Search>> all(BuildContext? context) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Search>> get(BuildContext? context, String id) {
|
||||
return service.get("$subPath/byWord?word=$id", true, context);
|
||||
}
|
||||
@override Future<APIResponse<Search>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Search>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Search>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
|
||||
}
|
||||
36
lib/core/services/specialized_services/shared_service.dart
Normal file
36
lib/core/services/specialized_services/shared_service.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
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/shared.dart';
|
||||
|
||||
class SharedService extends AbstractService<CollaborativeArea> {
|
||||
@override APIService<CollaborativeArea> service = APIService<CollaborativeArea>(
|
||||
baseURL: const String.fromEnvironment('COLLABORATIVE_AREA_HOST', defaultValue: 'http://localhost:8080/shared')
|
||||
);
|
||||
@override String subPath = "/collaborative_area/";
|
||||
|
||||
Future<APIResponse<CollaborativeArea>> addWorkspace(BuildContext? context, String id, String id2) {
|
||||
return service.post("$subPath$id/workspace/$id2", {}, context);
|
||||
}
|
||||
|
||||
Future<APIResponse<CollaborativeArea>> addWorkflow(BuildContext? context, String id, String id2) {
|
||||
return service.post("$subPath$id/workflow/$id2", {}, context);
|
||||
}
|
||||
|
||||
Future<APIResponse<CollaborativeArea>> addPeer(BuildContext? context, String id, String id2) {
|
||||
return service.post("$subPath$id/peer/$id2", {}, context);
|
||||
}
|
||||
|
||||
Future<APIResponse<CollaborativeArea>> removeWorkspace(BuildContext? context, String id, String id2) {
|
||||
return service.delete("$subPath$id/workspace/$id2", context);
|
||||
}
|
||||
|
||||
Future<APIResponse<CollaborativeArea>> removeWorkflow(BuildContext? context, String id, String id2) {
|
||||
return service.delete("$subPath$id/workflow/$id2", context);
|
||||
}
|
||||
|
||||
Future<APIResponse<CollaborativeArea>> removePeer(BuildContext? context, String id, String id2) {
|
||||
return service.delete("$subPath$id/peer/$id2", context);
|
||||
}
|
||||
}
|
||||
@@ -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:8080/scheduler')
|
||||
);
|
||||
@override String subPath = "/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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
|
||||
class SchedulerService extends AbstractService<WorkflowExecution> {
|
||||
@override APIService<WorkflowExecution> service = APIService<WorkflowExecution>(
|
||||
baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8080/scheduler')
|
||||
);
|
||||
@override String subPath = "/";
|
||||
|
||||
Future<APIResponse<WorkflowExecution>> schedule(BuildContext? context, String id, Map<String, dynamic> body, Map<String, dynamic> params) {
|
||||
print("$subPath$id");
|
||||
return service.post("$subPath$id", body, context);
|
||||
}
|
||||
|
||||
@override Future<APIResponse<WorkflowExecution>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override Future<APIResponse<WorkflowExecution>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<WorkflowExecution>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
|
||||
class WorflowService extends AbstractService<RawData> {
|
||||
@override APIService<RawData> service = APIService<RawData>(
|
||||
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:49618')
|
||||
class WorflowService extends AbstractService<Workflow> {
|
||||
@override APIService<Workflow> service = APIService<Workflow>(
|
||||
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8080/workflow')
|
||||
);
|
||||
@override String subPath = "/v1/workflow/";
|
||||
@override Future<APIResponse<RawData>> all(BuildContext? context) {
|
||||
return service.get(subPath, true, context);
|
||||
}
|
||||
@override Future<APIResponse<RawData>> get(BuildContext? context, String id) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<RawData>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
String path = "?";
|
||||
for (var key in params.keys) { path += "$key=${params[key]}&"; }
|
||||
return service.post("$subPath$path", body, context);
|
||||
}
|
||||
@override Future<APIResponse<RawData>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<RawData>> delete(BuildContext? context, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override String subPath = "/";
|
||||
}
|
||||
@@ -1,30 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/api_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/workspace.dart';
|
||||
|
||||
class WorkspaceService extends AbstractService<Workspace> {
|
||||
@override APIService<Workspace> service = APIService<Workspace>(
|
||||
baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:49618')
|
||||
baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:8080/workspace')
|
||||
);
|
||||
@override String subPath = "/v1/workspace/";
|
||||
|
||||
@override Future<APIResponse<Workspace>> all(BuildContext? context) {
|
||||
return service.get("$subPath/list", true, context);
|
||||
}
|
||||
@override Future<APIResponse<Workspace>> get(BuildContext? context, String id) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Workspace>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
String path = "?";
|
||||
for (var key in params.keys) { path += "$key=${params[key]}&"; }
|
||||
return service.post("$subPath$path", body, context);
|
||||
}
|
||||
@override Future<APIResponse<Workspace>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<Workspace>> delete(BuildContext? context, Map<String, String> params) {
|
||||
String path = "?";
|
||||
for (var key in params.keys) { path += "$key=${params[key]}&"; }
|
||||
return service.delete("$subPath$path", context);
|
||||
}
|
||||
@override String subPath = "/";
|
||||
}
|
||||
149
lib/main.dart
149
lib/main.dart
@@ -1,32 +1,42 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:localstorage/localstorage.dart';
|
||||
import 'package:oc_front/core/models/shared_workspace_local.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/sections/header/menu.dart';
|
||||
import 'package:oc_front/core/sections/left_menu.dart';
|
||||
import 'package:oc_front/core/services/auth.service.dart';
|
||||
import 'package:oc_front/core/services/enum_service.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
import 'package:oc_front/core/sections/end_drawer.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:desktop_window/desktop_window.dart' if (kIsWeb) '';
|
||||
import 'package:oc_front/widgets/dialog/login.dart';
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
void main() {
|
||||
// Run `LinuxWebViewPlugin.initialize()` first before creating a WebView.
|
||||
await initLocalStorage();
|
||||
runApp(const MyApp());
|
||||
}
|
||||
GlobalKey<MainPageState>? mainKey;
|
||||
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!kIsWeb) { DesktopWindow.setMinWindowSize(const Size(400, 400)); }
|
||||
return MaterialApp.router(
|
||||
routerConfig: GoRouter( routes: AppRouter.routes ),
|
||||
);
|
||||
AuthService.init();
|
||||
EnumService.init();
|
||||
SearchConstants.clear();
|
||||
return MaterialApp.router( routerConfig: GoRouter( routes: AppRouter.routes ) );
|
||||
}
|
||||
}
|
||||
// ignore: must_be_immutable
|
||||
class MainPage extends StatefulWidget {
|
||||
Widget page;
|
||||
MainPage({super.key, required this.page});
|
||||
Widget? page;
|
||||
MainPage({Key? key, required this.page}) : super(key: GlobalKey<MainPageState>());
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
@@ -38,10 +48,40 @@ class MainPage extends StatefulWidget {
|
||||
// always marked "final".
|
||||
|
||||
@override
|
||||
State<MainPage> createState() => _MainPageState();
|
||||
State<MainPage> createState() => MainPageState();
|
||||
}
|
||||
|
||||
class _MainPageState extends State<MainPage> {
|
||||
var darkColor = Color.fromRGBO(26, 83, 92, 1);
|
||||
var lightColor = Color.fromRGBO(78, 205, 196, 1);
|
||||
var darkMidColor = Color.fromRGBO(44, 83, 100, 1);
|
||||
var midColor = Colors.grey.shade300;
|
||||
var redColor = Color.fromRGBO(255, 107, 107, 1);
|
||||
|
||||
double getWidth(BuildContext context) {
|
||||
return MediaQuery.of(context).size.width <= 800 ? 800 : MediaQuery.of(context).size.width;
|
||||
}
|
||||
|
||||
double getHeight(BuildContext context) {
|
||||
return MediaQuery.of(context).size.height <= 400 ? 400 : MediaQuery.of(context).size.height;
|
||||
}
|
||||
|
||||
double getMainHeight(BuildContext context) {
|
||||
return getHeight(context) - HeaderConstants.height;
|
||||
}
|
||||
double getMainWidth(BuildContext context) {
|
||||
return getWidth(context) - 50;
|
||||
}
|
||||
bool loginIsSet = false;
|
||||
class MainPageState extends State<MainPage> {
|
||||
bool isCtrl = false;
|
||||
final FocusNode node = FocusNode();
|
||||
@override
|
||||
void initState() {
|
||||
mainKey = widget.key as GlobalKey<MainPageState>?;
|
||||
node.requestFocus();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
@@ -49,32 +89,63 @@ class _MainPageState extends State<MainPage> {
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
WorkspaceLocal.init(context);
|
||||
// than having to individually change instances of widgets.i
|
||||
scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
endDrawer: EndDrawerWidget(),
|
||||
body: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
//
|
||||
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
HeaderWidget(),
|
||||
widget.page // CatalogPageWidget(),
|
||||
],
|
||||
),
|
||||
);
|
||||
isCtrl = false;
|
||||
if (!AuthService.isConnected() && !loginIsSet) {
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
loginIsSet = true;
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context ?? context, builder: (context) {
|
||||
return AlertDialog(
|
||||
insetPadding: EdgeInsets.zero,
|
||||
backgroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)),
|
||||
title: LoginWidget());
|
||||
});
|
||||
});
|
||||
}
|
||||
return FutureBuilder(future: AuthService.init(),
|
||||
builder: (e, s) {
|
||||
WorkspaceLocal.init(context, false);
|
||||
HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) || AppRouter.currentRoute.factory.searchFill() ? 50 : 100;
|
||||
return Scaffold( key: scaffoldKey, endDrawer: EndDrawerWidget(), body:
|
||||
SingleChildScrollView(
|
||||
controller: ScrollController(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SingleChildScrollView(
|
||||
child: Column( children: [
|
||||
HeaderMenuWidget(),
|
||||
Row( children : [
|
||||
Container( padding: const EdgeInsets.symmetric(vertical: 30),
|
||||
decoration: BoxDecoration( color: darkColor),
|
||||
width: 50, height: getHeight(context) - 50,
|
||||
child: SingleChildScrollView( child: LeftMenuWidget() )),
|
||||
SizedBox( width: getMainWidth(context), height: getHeight(context) - 50,
|
||||
child: KeyboardListener(
|
||||
focusNode: node,
|
||||
onKeyEvent: (event) async {
|
||||
if ( event.logicalKey == LogicalKeyboardKey.controlLeft ) {
|
||||
isCtrl = (event is KeyDownEvent);
|
||||
node.requestFocus();
|
||||
} else if( (event is KeyDownEvent) && event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
AppRouter.currentRoute.factory.search(context, isCtrl);
|
||||
node.requestFocus();
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
HeaderWidget(),
|
||||
widget.page ?? Container() // CatalogPageWidget(),
|
||||
],
|
||||
),
|
||||
)),
|
||||
])
|
||||
])
|
||||
)
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer' as developer;
|
||||
|
||||
abstract class SerializerDeserializer<T> {
|
||||
T deserialize(dynamic json);
|
||||
|
||||
100
lib/models/logs.dart
Normal file
100
lib/models/logs.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:json_string/json_string.dart';
|
||||
|
||||
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 {
|
||||
"result": toListJson(result),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Logs extends SerializerDeserializer<Logs> {
|
||||
String? level;
|
||||
List<Log> logs = [];
|
||||
Logs({
|
||||
this.level,
|
||||
this.logs = const [],
|
||||
});
|
||||
|
||||
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"] : "",
|
||||
logs: json.containsKey("values") ? fromListJson(json["values"], Log()) : [],
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"level": level,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Log extends SerializerDeserializer<Log> {
|
||||
DateTime? timestamp;
|
||||
String? message;
|
||||
|
||||
String? level;
|
||||
String? rawMessage;
|
||||
Map<String, dynamic> map = {};
|
||||
Log({
|
||||
this.timestamp,
|
||||
this.message,
|
||||
this.rawMessage,
|
||||
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()})\nCreated at ${j["Created"].toString().replaceAllMapped(RegExp(r'\(\w+\)'), (match) { return ''; }).replaceAllMapped(RegExp(r'\+\w+'), (match) { return ''; })}; Started 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(); }
|
||||
var l = Log(
|
||||
timestamp: json.isNotEmpty ? DateTime.fromMillisecondsSinceEpoch(int.parse(json[0]) ~/ 1000) : null,
|
||||
message: json.length > 1 ? getMessage(json[1].toString()) : null,
|
||||
rawMessage : json.length > 1 ? json[1].toString() : null,
|
||||
);
|
||||
l.getMessage(l.message ?? "");
|
||||
return l;
|
||||
}
|
||||
@override Map<String, dynamic> serialize() { return { }; }
|
||||
}
|
||||
222
lib/models/resources/compute.dart
Normal file
222
lib/models/resources/compute.dart
Normal file
@@ -0,0 +1,222 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/enum_service.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
|
||||
class ComputeItem extends AbstractItem<ComputePricing, ComputePartnership, ComputeInstance, ComputeItem> {
|
||||
// special attributes
|
||||
int? infrastructureEnum;
|
||||
String? architecture;
|
||||
|
||||
ComputeItem({
|
||||
this.infrastructureEnum,
|
||||
this.architecture
|
||||
}): super();
|
||||
|
||||
@override String get topic => "compute";
|
||||
|
||||
@override deserialize(dynamic data) {
|
||||
try { data = data as Map<String, dynamic>;
|
||||
} catch (e) { return ComputeItem(); }
|
||||
var w = ComputeItem(
|
||||
infrastructureEnum: data.containsKey("infrastructure") ? EnumService.get("infrastructure", data["infrastructure"]) : null,
|
||||
architecture: data.containsKey("architecture") && data["architecture"] != null ? data["architecture"] : null,
|
||||
);
|
||||
w.mapFromJSON(data, ComputeInstance());
|
||||
if (w.logo != null) { // get image dimensions
|
||||
var image = Image.network(w.logo!);
|
||||
image.image
|
||||
.resolve(const ImageConfiguration())
|
||||
.addListener(
|
||||
ImageStreamListener(
|
||||
(ImageInfo info, bool _) {
|
||||
w.width = info.image.width.toDouble();
|
||||
w.height = info.image.height.toDouble();
|
||||
}));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"infrastructure": EnumService.enums["infrastructure"] != null
|
||||
&& EnumService.enums["infrastructure"]!["$infrastructureEnum"] != null ? EnumService.enums["infrastructure"]!["$infrastructureEnum"] : infrastructureEnum,
|
||||
"architecture": architecture,
|
||||
};
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
Map<String, dynamic> obj = infos();
|
||||
obj["infrastructure"] = infrastructureEnum;
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class ComputeInstance extends AbstractInstance<ComputePricing, ComputePartnership> {
|
||||
String? securityLevel;
|
||||
List<String>? powerSources = [];
|
||||
double? annualEnergyConsumption;
|
||||
Map<String,CPU> cpus = {};
|
||||
Map<String,GPU> gpus = {};
|
||||
List<ComputeNode> nodes = [];
|
||||
|
||||
ComputeInstance({
|
||||
this.securityLevel,
|
||||
this.powerSources = const [],
|
||||
this.annualEnergyConsumption,
|
||||
this.cpus = const {},
|
||||
this.gpus = const {},
|
||||
this.nodes = const [],
|
||||
}): super();
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"security_level": securityLevel,
|
||||
"power_sources": powerSources,
|
||||
"annual_co2_emissions": annualEnergyConsumption,
|
||||
"cpus": toMapJson(cpus),
|
||||
"gpus": toMapJson(gpus),
|
||||
"nodes": toListJson(nodes),
|
||||
"inputs": toListJson(inputs),
|
||||
"outputs": toListJson(outputs),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
ComputeInstance deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ComputeInstance(); }
|
||||
var w = ComputeInstance(
|
||||
securityLevel: json.containsKey("security_level") && json["security_level"] != null ? json["security_level"] : null,
|
||||
powerSources: json.containsKey("power_sources") && json["power_sources"] != null ? List<String>.from(json["power_sources"]) : [],
|
||||
annualEnergyConsumption: json.containsKey("annual_co2_emissions") && json["annual_co2_emissions"] != null ? json["annual_co2_emissions"] : null,
|
||||
//cpus: json.containsKey("cpus") && json["cpus"] != null ? fromMapJson(json["cpus"], CPU()) : {},
|
||||
// gpus: json.containsKey("gpus") && json["gpus"] != null ? fromMapJson(json["gpus"], GPU()) : {},
|
||||
//nodes: json.containsKey("nodes") && json["nodes"] != null ? fromListJson(json["nodes"], ComputeNode()) : [],
|
||||
);
|
||||
w.mapFromJSON(json, ComputePartnership());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
var obj = infos();
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class ComputePartnership extends AbstractPartnerShip<ComputePricing> {
|
||||
Map<String, dynamic> maxAllowedCPUsCores = {};
|
||||
Map<String, dynamic> maxAllowedGPUsMemoryGB = {};
|
||||
double? maxAllowedRAM;
|
||||
|
||||
ComputePartnership({
|
||||
this.maxAllowedCPUsCores = const {},
|
||||
this.maxAllowedGPUsMemoryGB = const {},
|
||||
this.maxAllowedRAM,
|
||||
}): super();
|
||||
|
||||
@override
|
||||
ComputePartnership deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ComputePartnership(); }
|
||||
var w = ComputePartnership(
|
||||
maxAllowedCPUsCores: json.containsKey("allowed_cpus") && json["allowed_cpus"] != null ? json["allowed_cpus"] : {},
|
||||
maxAllowedGPUsMemoryGB: json.containsKey("allowed_gpus") && json["allowed_gpus"] != null ? json["allowed_gpus"] : {},
|
||||
maxAllowedRAM: json.containsKey("allowed_ram") && json["allowed_ram"] != null ? double.parse("${json["allowed_ram"]}") : null,
|
||||
);
|
||||
w.mapFromJSON(json, ComputePricing());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
Map<String, dynamic> obj = {
|
||||
"allowed_cpus": maxAllowedCPUsCores,
|
||||
"allowed_gpus": maxAllowedGPUsMemoryGB,
|
||||
"allowed_ram": maxAllowedRAM,
|
||||
};
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ComputePricing extends AbstractPricing {
|
||||
Map<String, dynamic> cpusPrice = {};
|
||||
Map<String, dynamic> gpusPrice = {};
|
||||
double? ramPrice;
|
||||
|
||||
ComputePricing({
|
||||
this.cpusPrice = const {},
|
||||
this.gpusPrice = const {},
|
||||
this.ramPrice,
|
||||
});
|
||||
|
||||
@override ComputePricing deserialize(json) {
|
||||
var w = ComputePricing(
|
||||
cpusPrice: json.containsKey("cpus") && json["cpus"] != null ? json["cpus"] : {},
|
||||
gpusPrice: json.containsKey("gpus") && json["gpus"] != null ? json["gpus"] : {},
|
||||
ramPrice: json.containsKey("ram") && json["ram"] != null ? json["ram"] : null,
|
||||
);
|
||||
w.mapFromJSON(json);
|
||||
return w;
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
var obj = {
|
||||
"cpus": cpusPrice,
|
||||
"gpus": gpusPrice,
|
||||
"ram": ramPrice,
|
||||
};
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class ComputeNode extends SerializerDeserializer<ComputeNode> {
|
||||
String? name;
|
||||
int? quantity;
|
||||
Map<String,dynamic> cpus = {};
|
||||
Map<String,dynamic> gpus = {};
|
||||
RAM? ram;
|
||||
|
||||
ComputeNode({
|
||||
this.cpus = const {},
|
||||
this.gpus = const {},
|
||||
this.ram,
|
||||
this.name,
|
||||
this.quantity,
|
||||
});
|
||||
|
||||
@override
|
||||
ComputeNode deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ComputeNode(); }
|
||||
return ComputeNode(
|
||||
name: json.containsKey("name") && json["name"] != null ? json["name"] : null,
|
||||
quantity: json.containsKey("quantity") && json["quantity"] != null ? json["quantity"] : null,
|
||||
cpus: json.containsKey("cpus") && json["cpus"] != null ? fromMapJson(json["cpus"], CPU()) : {},
|
||||
gpus: json.containsKey("gpus") && json["gpus"] != null ? fromMapJson(json["gpus"], GPU()) : {},
|
||||
ram: json.containsKey("ram") && json["ram"] != null ? RAM().deserialize(json["ram"]) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"name": name,
|
||||
"quantity": quantity,
|
||||
"cpus": cpus,
|
||||
"gpus": gpus,
|
||||
"ram": ram!.serialize(),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
166
lib/models/resources/data.dart
Normal file
166
lib/models/resources/data.dart
Normal file
@@ -0,0 +1,166 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
|
||||
class DataItem extends AbstractItem<DataPricing, DataPartnership, DataInstance, DataItem> {
|
||||
// special attributes
|
||||
String? type;
|
||||
String? source;
|
||||
String? quality;
|
||||
bool openData = false;
|
||||
bool static = false;
|
||||
bool personalData = false;
|
||||
bool anonymizedPersonalData = false;
|
||||
double? size;
|
||||
String? example;
|
||||
DateTime? updatePeriod;
|
||||
|
||||
DataItem({
|
||||
this.type,
|
||||
this.source,
|
||||
this.quality,
|
||||
this.openData = false,
|
||||
this.static = false,
|
||||
this.personalData = false,
|
||||
this.anonymizedPersonalData = false,
|
||||
this.size,
|
||||
this.example,
|
||||
this.updatePeriod,
|
||||
}): super();
|
||||
|
||||
@override String get topic => "data";
|
||||
|
||||
@override deserialize(dynamic data) {
|
||||
try { data = data as Map<String, dynamic>;
|
||||
} catch (e) { return DataItem(); }
|
||||
var w = DataItem(
|
||||
type: data.containsKey("type") && data["type"] != null ? data["type"] : null,
|
||||
source: data.containsKey("source") && data["source"] != null ? data["source"] : null,
|
||||
quality: data.containsKey("quality") && data["quality"] != null ? data["quality"] : null,
|
||||
openData: data.containsKey("open_data") && data["open_data"] != null ? data["open_data"] : false,
|
||||
static: data.containsKey("static") && data["static"] != null ? data["static"] : false,
|
||||
personalData: data.containsKey("personal_data") && data["l"] != null ? data["personal_data"] : false,
|
||||
anonymizedPersonalData: data.containsKey("anonymized_personal_data") && data["anonymized_personal_data"] != null ? data["anonymized_personal_data"] : false,
|
||||
size: data.containsKey("size") && data["size"] != null ? data["size"] : null,
|
||||
example: data.containsKey("example") && data["example"] != null ? data["example"] : null,
|
||||
updatePeriod: data.containsKey("update_period") && data["update_period"] != null ? DateTime.parse(data["update_period"]) : null,
|
||||
);
|
||||
w.mapFromJSON(data, DataInstance());
|
||||
if (w.logo != null) { // get image dimensions
|
||||
var image = Image.network(w.logo!);
|
||||
image.image
|
||||
.resolve(const ImageConfiguration())
|
||||
.addListener(
|
||||
ImageStreamListener(
|
||||
(ImageInfo info, bool _) {
|
||||
w.width = info.image.width.toDouble();
|
||||
w.height = info.image.height.toDouble();
|
||||
}));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"type": type,
|
||||
"quality": quality,
|
||||
"open_data": openData,
|
||||
"static": static,
|
||||
"personal_data": personalData,
|
||||
"anonymized_personal_data": anonymizedPersonalData,
|
||||
"size": size,
|
||||
"example": example,
|
||||
"update_period": updatePeriod?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var obj = infos();
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class DataInstance extends AbstractInstance<DataPricing, DataPartnership> {
|
||||
String? source;
|
||||
DataInstance(
|
||||
{this.source}
|
||||
): super();
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"inputs": toListJson(inputs),
|
||||
"outputs": toListJson(outputs),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
DataInstance deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return DataInstance(); }
|
||||
var w = DataInstance(
|
||||
source: json.containsKey("source") && json["source"] != null ? json["source"] : null,
|
||||
);
|
||||
w.mapFromJSON(json, DataPartnership());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
var obj = toJSON();
|
||||
obj["source"] = source;
|
||||
obj.addAll(infos());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class DataPartnership extends AbstractPartnerShip<DataPricing> {
|
||||
double? maxDownloadableGBAllowed;
|
||||
bool personalDataAllowed = false;
|
||||
bool anonymizedPersonalDataAllowed = false;
|
||||
|
||||
DataPartnership({
|
||||
this.maxDownloadableGBAllowed,
|
||||
this.personalDataAllowed = false,
|
||||
this.anonymizedPersonalDataAllowed = false,
|
||||
}): super();
|
||||
|
||||
@override
|
||||
DataPartnership deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return DataPartnership(); }
|
||||
var w = DataPartnership(
|
||||
maxDownloadableGBAllowed: json.containsKey("max_downloadable_gb_allowed") && json["max_downloadable_gb_allowed"] != null ? json["max_downloadable_gb_allowed"] : null,
|
||||
personalDataAllowed: json.containsKey("personal_data_allowed") && json["personal_data_allowed"] != null ? json["personal_data_allowed"] : false,
|
||||
anonymizedPersonalDataAllowed: json.containsKey("anonymized_personal_data_allowed") && json["anonymized_personal_data_allowed"] != null ? json["anonymized_personal_data_allowed"] : false,
|
||||
);
|
||||
w.mapFromJSON(json, DataPricing());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
Map<String, dynamic> obj = {
|
||||
"max_downloadable_gb_allowed": maxDownloadableGBAllowed,
|
||||
"personal_data_allowed": personalDataAllowed,
|
||||
"anonymized_personal_data_allowed": anonymizedPersonalDataAllowed,
|
||||
};
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class DataPricing extends AbstractPricing {
|
||||
@override DataPricing deserialize(json) {
|
||||
var w = DataPricing();
|
||||
w.mapFromJSON(json);
|
||||
return w;
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return toJSON();
|
||||
}
|
||||
}
|
||||
357
lib/models/resources/processing.dart
Normal file
357
lib/models/resources/processing.dart
Normal file
@@ -0,0 +1,357 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/enum_service.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
|
||||
class ProcessingItem extends AbstractItem<ProcessingPricing, ProcessingPartnership, ProcessingInstance, ProcessingItem> {
|
||||
// special attributes
|
||||
int? infrastructureEnum;
|
||||
bool isService = false;
|
||||
bool openSource = false;
|
||||
String? license;
|
||||
String? maturity;
|
||||
ProcessingUsage? usage;
|
||||
|
||||
ProcessingItem({
|
||||
this.infrastructureEnum,
|
||||
this.isService = false,
|
||||
this.openSource = false,
|
||||
this.license,
|
||||
this.maturity,
|
||||
this.usage,
|
||||
}): super();
|
||||
|
||||
@override String get topic => "processing";
|
||||
|
||||
@override deserialize(dynamic data) {
|
||||
try { data = data as Map<String, dynamic>;
|
||||
} catch (e) { return ProcessingItem(); }
|
||||
var w = ProcessingItem(
|
||||
infrastructureEnum: data.containsKey("infrastructure") ? EnumService.get("infrastructure", data["infrastructure"]) : null,
|
||||
isService: data.containsKey("is_service") && data["is_service"] != null ? data["is_service"] : false,
|
||||
openSource: data.containsKey("open_source") && data["open_source"] != null ? data["open_source"] : false,
|
||||
license: data.containsKey("license") && data["license"] != null ? data["license"] : null,
|
||||
maturity: data.containsKey("maturity") && data["maturity"] != null ? data["maturity"] : null,
|
||||
usage: data.containsKey("usage") && data["usage"] != null ? ProcessingUsage().deserialize(data["usage"]) : null,
|
||||
);
|
||||
w.mapFromJSON(data, ProcessingInstance());
|
||||
if (w.logo != null) { // get image dimensions
|
||||
var image = Image.network(w.logo!);
|
||||
image.image
|
||||
.resolve(const ImageConfiguration())
|
||||
.addListener(
|
||||
ImageStreamListener(
|
||||
(ImageInfo info, bool _) {
|
||||
w.width = info.image.width.toDouble();
|
||||
w.height = info.image.height.toDouble();
|
||||
}));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"infrastructure": EnumService.enums["infrastructure"] != null
|
||||
&& EnumService.enums["infrastructure"]!["$infrastructureEnum"] != null ?
|
||||
EnumService.enums["infrastructure"]!["$infrastructureEnum"] : infrastructureEnum,
|
||||
"is_service": isService,
|
||||
"open_source": openSource,
|
||||
"license": license,
|
||||
"maturity": maturity,
|
||||
};
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var obj = infos();
|
||||
obj["infrastructure"] = infrastructureEnum;
|
||||
obj["usage"] = usage?.serialize();
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessingAccess extends SerializerDeserializer<ProcessingAccess> {
|
||||
Containered? container;
|
||||
|
||||
ProcessingAccess({
|
||||
this.container,
|
||||
});
|
||||
|
||||
@override ProcessingAccess deserialize(dynamic json) {
|
||||
try {
|
||||
json = json as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
return ProcessingAccess();
|
||||
}
|
||||
return ProcessingAccess(
|
||||
container: json.containsKey("container") && json["container"] != null ? Containered().deserialize(json["container"]) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"container": container?.serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessingInstance extends AbstractInstance<ProcessingPricing, ProcessingPartnership> {
|
||||
ProcessingAccess? access;
|
||||
ProcessingInstance(
|
||||
{this.access}
|
||||
): super();
|
||||
|
||||
@override
|
||||
ProcessingInstance deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ProcessingInstance(); }
|
||||
var w = ProcessingInstance();
|
||||
w.access = json.containsKey("access") && json["access"] != null ? ProcessingAccess().deserialize(json['access']) : null;
|
||||
w.mapFromJSON(json, ProcessingPartnership());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
var obj = toJSON();
|
||||
obj["access"] = access?.serialize();
|
||||
return obj;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"inputs": toListJson(inputs),
|
||||
"outputs": toListJson(outputs),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessingPartnership extends AbstractPartnerShip<ProcessingPricing> {
|
||||
ProcessingPartnership(): super();
|
||||
|
||||
@override
|
||||
ProcessingPartnership deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ProcessingPartnership(); }
|
||||
var w = ProcessingPartnership();
|
||||
w.mapFromJSON(json, ProcessingPricing());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessingPricing extends AbstractPricing {
|
||||
@override ProcessingPricing deserialize(json) {
|
||||
var w = ProcessingPricing();
|
||||
w.mapFromJSON(json);
|
||||
return w;
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessingUsage extends SerializerDeserializer<ProcessingUsage> {
|
||||
Map<String,CPU> cpus = {};
|
||||
Map<String,GPU> gpus = {};
|
||||
RAM? ram;
|
||||
double? storageSize;
|
||||
String? hypothesis;
|
||||
String? scalingModel;
|
||||
|
||||
ProcessingUsage({
|
||||
this.cpus = const {},
|
||||
this.gpus = const {},
|
||||
this.ram,
|
||||
this.storageSize,
|
||||
this.hypothesis,
|
||||
this.scalingModel,
|
||||
});
|
||||
|
||||
@override
|
||||
ProcessingUsage deserialize(json) {
|
||||
return ProcessingUsage(
|
||||
cpus: json.containsKey("cpus") && json["cpus"] != null ? fromMapJson(json["cpus"], CPU()) : {},
|
||||
gpus: json.containsKey("gpus") && json["gpus"] != null ? fromMapJson(json["gpus"], GPU()) : {},
|
||||
ram: json.containsKey("ram") && json["ram"] != null ? RAM().deserialize(json["ram"]) : null,
|
||||
storageSize: json.containsKey("storage_size") && json["storage_size"] != null ? json["storage_size"]?.toDouble() : null,
|
||||
hypothesis: json.containsKey("hypothesis") && json["hypothesis"] != null ? json["hypothesis"] : null,
|
||||
scalingModel: json.containsKey("scaling_model") && json["scaling_model"] != null ? json["scaling_model"] : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"cpus": toMapJson(cpus),
|
||||
"gpus": toMapJson(gpus),
|
||||
"ram": ram?.serialize(),
|
||||
"storage_size": storageSize,
|
||||
"hypothesis": hypothesis,
|
||||
"scaling_model": scalingModel,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CPU extends SerializerDeserializer<CPU> {
|
||||
CPU({
|
||||
this.cores,
|
||||
this.platform,
|
||||
this.architecture,
|
||||
this.minimumMemory,
|
||||
this.shared = false,
|
||||
});
|
||||
double? cores;
|
||||
String? platform;
|
||||
bool shared = false;
|
||||
String? architecture;
|
||||
double? minimumMemory;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return CPU(); }
|
||||
return CPU(
|
||||
cores: json.containsKey("cores") && json["cores"] != null ? json["cores"]?.toDouble() : null,
|
||||
platform: json.containsKey("platform") && json["platform"] != null ? json["platform"] : null,
|
||||
architecture: json.containsKey("architecture") && json["architecture"] != null ? json["architecture"] : null,
|
||||
minimumMemory: json.containsKey("minimumMemory") && json["minimumMemory"] != null ? json["minimumMemory"]?.toDouble() : null,
|
||||
shared: json.containsKey("shared") && json["shared"] != null ? json["shared"] : false,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"cores": cores,
|
||||
"platform": platform,
|
||||
"architecture": architecture,
|
||||
"minimumMemory": minimumMemory,
|
||||
"shared": shared,
|
||||
};
|
||||
}
|
||||
class GPU extends SerializerDeserializer<GPU> {
|
||||
GPU({
|
||||
this.cudaCores,
|
||||
this.memory,
|
||||
this.model,
|
||||
this.tensorCores,
|
||||
});
|
||||
double? cudaCores;
|
||||
double? memory;
|
||||
String? model;
|
||||
double? tensorCores;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return GPU(); }
|
||||
return GPU(
|
||||
cudaCores: json.containsKey("cuda_cores") && json["cuda_cores"] != null ? json["cuda_cores"]?.toDouble() : null,
|
||||
memory: json.containsKey("memory") && json["memory"] != null ? json["memory"]?.toDouble() : null,
|
||||
model: json.containsKey("model") && json["model"] != null ? json["model"] : null,
|
||||
tensorCores: json.containsKey("tensor_cores") && json["tensor_cores"] != null ? json["tensor_cores"]?.toDouble() : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"cuda_cores": cudaCores,
|
||||
"memory": memory,
|
||||
"model": model,
|
||||
"tensor_cores": tensorCores,
|
||||
};
|
||||
}
|
||||
class RAM extends SerializerDeserializer<RAM> {
|
||||
RAM({
|
||||
this.ecc = false,
|
||||
this.size,
|
||||
});
|
||||
bool ecc = false;
|
||||
double? size;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return RAM(); }
|
||||
return RAM(
|
||||
ecc: json.containsKey("ecc") && json["ecc"] != null ? json["ecc"] : false,
|
||||
size: json.containsKey("size") && json["size"] != null ? json["size"]?.toDouble() : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"ecc": ecc,
|
||||
"size": size,
|
||||
};
|
||||
}
|
||||
|
||||
class Expose extends SerializerDeserializer<Expose> {
|
||||
Expose({
|
||||
this.PAT,
|
||||
this.port,
|
||||
this.path,
|
||||
});
|
||||
|
||||
int? port;
|
||||
int? PAT;
|
||||
String? path;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Expose(); }
|
||||
return Expose(
|
||||
port: json.containsKey("port") && json["port"] != null ? json["port"] : null,
|
||||
PAT: json.containsKey("PAT") && json["PAT"] != null ? json["PAT"] : null,
|
||||
path: json.containsKey("reverse") && json["reverse"] != null ? json["reverse"] : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"port": port,
|
||||
"PAT": PAT,
|
||||
"reverse": path,
|
||||
};
|
||||
}
|
||||
|
||||
class Containered extends SerializerDeserializer<Containered> {
|
||||
Containered({
|
||||
this.image,
|
||||
this.args,
|
||||
this.command,
|
||||
this.env,
|
||||
this.volumes,
|
||||
this.exposes = const [],
|
||||
});
|
||||
|
||||
String? args;
|
||||
String? image;
|
||||
String? command;
|
||||
Map<String, dynamic>? env;
|
||||
Map<String, dynamic>? volumes;
|
||||
List<Expose> exposes = [];
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Containered(); }
|
||||
return Containered(
|
||||
args: json.containsKey("args") && json["args"] != null ? json["args"] : null,
|
||||
image: json.containsKey("image") && json["image"] != null ? json["image"] : null,
|
||||
command: json.containsKey("command") && json["command"] != null ? json["command"] : null,
|
||||
env: json.containsKey("env") && json["env"] != null ? json["env"] : null,
|
||||
volumes: json.containsKey("volumes") && json["volumes"] != null ? json["volumes"] : null,
|
||||
exposes: json.containsKey("exposes") && json["exposes"] != null ? fromListJson(json["exposes"], Expose()) : [],
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var w = {
|
||||
"args": args,
|
||||
"image": image,
|
||||
"command": command,
|
||||
"env": env,
|
||||
"volumes": volumes,
|
||||
"exposes": toListJson(exposes),
|
||||
};
|
||||
return w;
|
||||
}
|
||||
}
|
||||
529
lib/models/resources/resources.dart
Normal file
529
lib/models/resources/resources.dart
Normal file
@@ -0,0 +1,529 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/data.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
import 'package:oc_front/models/resources/workflow.dart';
|
||||
|
||||
class Resource implements SerializerDeserializer<Resource> {
|
||||
List<DataItem> datas = [];
|
||||
List<ProcessingItem> processings = [];
|
||||
List<StorageItem> storages = [];
|
||||
List<ComputeItem> computes = [];
|
||||
List<WorkflowItem> workflows = [];
|
||||
|
||||
Resource({
|
||||
this.datas = const [],
|
||||
this.processings = const [],
|
||||
this.storages = const [],
|
||||
this.computes = const [],
|
||||
this.workflows = const [],
|
||||
});
|
||||
|
||||
@override Resource deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Resource(); }
|
||||
return Resource(
|
||||
computes: json.containsKey("compute_resource") ? fromListJson(json["compute_resource"], ComputeItem()) : [],
|
||||
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 {
|
||||
"compute_resource": toListJson<ComputeItem>(computes),
|
||||
"data_resource": toListJson<DataItem>(datas),
|
||||
"processing_resource": toListJson<ProcessingItem>(processings),
|
||||
"storage_resource": toListJson<StorageItem>(storages),
|
||||
"workflow_resource": toListJson<WorkflowItem>(workflows),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Owner extends SerializerDeserializer<Owner> {
|
||||
String? name;
|
||||
String? logo;
|
||||
|
||||
Owner({
|
||||
this.name,
|
||||
this.logo,
|
||||
});
|
||||
|
||||
@override Owner deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Owner(); }
|
||||
return Owner(
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"name": name,
|
||||
"logo": logo,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Infos {
|
||||
Map<String, dynamic> infos();
|
||||
}
|
||||
|
||||
class Artifact extends SerializerDeserializer<Artifact> {
|
||||
String? attrPath;
|
||||
String? attrFrom;
|
||||
bool readOnly = true;
|
||||
|
||||
Artifact({
|
||||
this.attrPath,
|
||||
this.attrFrom,
|
||||
this.readOnly = true,
|
||||
});
|
||||
|
||||
@override Artifact deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Artifact(); }
|
||||
return Artifact(
|
||||
attrPath: json.containsKey("attr_path") ? json["attr_path"] : null,
|
||||
attrFrom: json.containsKey("attr_from") ? json["attr_from"] : null,
|
||||
readOnly: json.containsKey("readonly") ? json["readonly"] : true,
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"attr_path": attrPath,
|
||||
"attr_from": attrFrom,
|
||||
"readonly": readOnly,
|
||||
};
|
||||
}
|
||||
}
|
||||
class Param extends SerializerDeserializer<Param> {
|
||||
String? name;
|
||||
String? attr;
|
||||
dynamic value;
|
||||
String? origin;
|
||||
bool optionnal = false;
|
||||
bool readOnly = true;
|
||||
|
||||
Param({
|
||||
this.name,
|
||||
this.attr,
|
||||
this.value,
|
||||
this.origin,
|
||||
this.optionnal = false,
|
||||
this.readOnly = true,
|
||||
});
|
||||
|
||||
@override Param deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Param(); }
|
||||
return Param(
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
attr: json.containsKey("attr") ? json["attr"] : null,
|
||||
value: json.containsKey("value") ? json["value"] : null,
|
||||
origin: json.containsKey("origin") ? json["origin"] : null,
|
||||
optionnal: json.containsKey("optionnal") ? json["optionnal"] : false,
|
||||
readOnly: json.containsKey("readonly") ? json["readonly"] : false,
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"name": name,
|
||||
"attr": attr,
|
||||
"value": value,
|
||||
"origin": origin,
|
||||
"optionnal": optionnal,
|
||||
"readonly": readOnly,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Credential extends SerializerDeserializer<Credential> {
|
||||
String? login;
|
||||
String? password;
|
||||
|
||||
Credential({
|
||||
this.login,
|
||||
this.password,
|
||||
});
|
||||
|
||||
@override
|
||||
Credential deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Credential(); }
|
||||
return Credential(
|
||||
login: json.containsKey("login") ? json["login"] : null,
|
||||
password: json.containsKey("password") ? json["password"] : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"login": login,
|
||||
"password": password,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractItem<X extends AbstractPricing, Y extends AbstractPartnerShip<X>, S extends AbstractInstance<X,Y>, T extends FlowData> extends FlowData implements SerializerDeserializer<T>, Infos {
|
||||
String? id;
|
||||
String? name;
|
||||
String? logo;
|
||||
String? type;
|
||||
String? creatorID;
|
||||
String? updaterID;
|
||||
DateTime? createdAt;
|
||||
DateTime? updatedAt;
|
||||
List<Owner> owners;
|
||||
String? description;
|
||||
String? restrictions;
|
||||
String? shortDescription;
|
||||
int selectedInstance = 0;
|
||||
|
||||
List<AbstractInstance<X,Y>> instances = [];
|
||||
|
||||
String get topic => "";
|
||||
|
||||
AbstractItem({
|
||||
this.id,
|
||||
this.type,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.creatorID,
|
||||
this.updaterID,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.description,
|
||||
this.shortDescription,
|
||||
this.owners = const [],
|
||||
this.selectedInstance = 0,
|
||||
});
|
||||
|
||||
void addEnv(List<dynamic> infos) {
|
||||
var inst = getSelectedInstance();
|
||||
if (inst == null) { return; }
|
||||
inst.env = [];
|
||||
for (var info in infos) {
|
||||
inst.env.add(Param(name: info["name"], attr: info["attr"], value: info["value"],
|
||||
origin: info["origin"], optionnal: info["optionnal"], readOnly: info["readonly"]));
|
||||
}
|
||||
}
|
||||
|
||||
AbstractInstance<X,Y>? getSelectedInstance() {
|
||||
if (selectedInstance == -1) { return instances.isEmpty ? null : instances[0]; }
|
||||
return instances.isNotEmpty ? instances[selectedInstance] : null;
|
||||
}
|
||||
|
||||
@override String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
|
||||
@override String getType() {
|
||||
return type ?? "";
|
||||
}
|
||||
|
||||
|
||||
@override String getName() {
|
||||
return name ?? "";
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos();
|
||||
|
||||
double? width;
|
||||
double? height;
|
||||
@override
|
||||
double? getWidth() {
|
||||
return width;
|
||||
}
|
||||
@override
|
||||
double? getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
Map<String, dynamic> setVariable(String key, dynamic value, Map<String, dynamic> map) {
|
||||
map[key] = value;
|
||||
return map;
|
||||
}
|
||||
|
||||
dynamic getVariable(String key, Map<String, dynamic> map) {
|
||||
return map[key];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJSON() {
|
||||
return {
|
||||
"id": id,
|
||||
"type": type ?? topic,
|
||||
"name": name,
|
||||
"logo": logo,
|
||||
"owners": toListJson(owners),
|
||||
"creator_id": creatorID,
|
||||
"updater_id": updaterID,
|
||||
"creation_date": createdAt?.toIso8601String(),
|
||||
"update_date": updatedAt?.toIso8601String(),
|
||||
"description": description,
|
||||
"short_description": shortDescription,
|
||||
"selected_instance": selectedInstance,
|
||||
"instances": instances.map((e) => e.serialize()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
void mapFromJSON(dynamic json, S ex) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return; }
|
||||
this.id = json.containsKey("id") ? json["id"] : null;
|
||||
this.type = json.containsKey("type") ? json["type"] : topic;
|
||||
this.name = json.containsKey("name") ? json["name"] : null;
|
||||
this.logo = json.containsKey("logo") ? json["logo"] : null;
|
||||
this.creatorID = json.containsKey("creator_id") ? json["creator_id"] : null;
|
||||
this.updaterID = json.containsKey("updater_id") ? json["updater_id"] : null;
|
||||
this.description = json.containsKey("description") ? json["description"] : null;
|
||||
this.owners = json.containsKey("owners") ? fromListJson(json["owners"], Owner()) : [];
|
||||
this.instances = json.containsKey("instances") ? fromListJson(json["instances"], ex) : [];
|
||||
this.updatedAt = json.containsKey("update_date") ? DateTime.parse(json["update_date"]) : null;
|
||||
this.selectedInstance = json.containsKey("selected_instance") ? json["selected_instance"] : 0;
|
||||
this.shortDescription = json.containsKey("short_description") ? json["short_description"] : null;
|
||||
this.createdAt = json.containsKey("creation_date") ? DateTime.parse(json["creation_date"]) : null;
|
||||
}
|
||||
}
|
||||
|
||||
class Location extends SerializerDeserializer<Location> {
|
||||
double? latitude;
|
||||
double? longitude;
|
||||
|
||||
Location({
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
});
|
||||
|
||||
@override
|
||||
Location deserialize(json) {
|
||||
return Location(
|
||||
latitude: json.containsKey("latitude") ? json["latitude"] : null,
|
||||
longitude: json.containsKey("longitude") ? json["longitude"] : null,
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"latitude": latitude,
|
||||
"longitude": longitude,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractInstance<X extends AbstractPricing, S extends AbstractPartnerShip<X>> extends SerializerDeserializer<AbstractInstance<X,S>> implements Infos {
|
||||
String? id;
|
||||
String? name;
|
||||
int? countryCode;
|
||||
Location? location;
|
||||
List<S> partnerships = [];
|
||||
List<Param> env = [];
|
||||
List<Param> inputs = [];
|
||||
List<Param> outputs = [];
|
||||
Credential? credential;
|
||||
|
||||
|
||||
bool isEnv(String key) {
|
||||
for (var e in env) {
|
||||
if (e.name?.contains(key) ?? false || key.contains(e.name ?? "none")) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isEnvAttr(String attr, String origin, bool isOrigin) {
|
||||
for (var e in env) {
|
||||
if (e.attr == attr && ((isOrigin && e.origin != null) || (!isOrigin && e.origin == origin))) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos();
|
||||
|
||||
void mapFromJSON(dynamic json, S ex) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return; }
|
||||
this.countryCode = json.containsKey("country_code") ? json["country_code"] : null;
|
||||
this.id = json.containsKey("id") ? json["id"] : null;
|
||||
this.name = json.containsKey("name") ? json["name"] : null;
|
||||
this.env = json.containsKey("env") ? fromListJson(json["env"], Param()) : [];
|
||||
this.inputs = json.containsKey("inputs") ? fromListJson(json["inputs"], Param()) : [];
|
||||
this.outputs = json.containsKey("outputs") ? fromListJson(json["outputs"], Param()) : [];
|
||||
this.location = json.containsKey("location") ? Location().deserialize(json["location"]) : null;
|
||||
this.credential = json.containsKey("credential") ? Credential().deserialize(json["credential"]) : null;
|
||||
this.partnerships = json.containsKey("partnerships") ? fromListJson(json["partnerships"], ex) : [];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJSON() {
|
||||
return {
|
||||
"country_code": countryCode,
|
||||
"id": id,
|
||||
"name": name,
|
||||
"location": location?.serialize(),
|
||||
"env": toListJson(env),
|
||||
"inputs": toListJson(inputs),
|
||||
"outputs": toListJson(outputs),
|
||||
"credential": credential?.serialize(), // TODO CREDENTIAL FORM
|
||||
"partnerships": partnerships.map((e) => e.serialize()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractPartnerShip<S extends AbstractPricing> extends SerializerDeserializer<AbstractPartnerShip<S>> {
|
||||
String? namespace;
|
||||
List<AbstractPricing> pricings = [];
|
||||
|
||||
void mapFromJSON(dynamic json, S ex) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return; }
|
||||
this.namespace = json.containsKey("namespace") ? json["namespace"] : null;
|
||||
this.pricings = json.containsKey("pricings") ? fromListJson(json["pricings"], ex) : [];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJSON() {
|
||||
return {
|
||||
"namespace": namespace,
|
||||
"pricings": pricings,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractPricing extends SerializerDeserializer<AbstractPricing> {
|
||||
PricingStrategy? pricing;
|
||||
int? refundTypeEnum;
|
||||
int? refundRatio;
|
||||
List<dynamic> additionnalRefundTypeEnum = [];
|
||||
int? privilegeStrategyEnum;
|
||||
int? garantedDelaySecond;
|
||||
bool exceeding = false;
|
||||
int? exceedingRatio;
|
||||
|
||||
void mapFromJSON(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return; }
|
||||
pricing = json.containsKey("pricing") ? PricingStrategy().deserialize(json["pricing"]) : null;
|
||||
refundTypeEnum = json.containsKey("refund_type") ? json["refund_type"] : null;
|
||||
refundRatio = json.containsKey("refund_ratio") ? json["refund_ratio"] : null;
|
||||
additionnalRefundTypeEnum = json.containsKey("additionnal_refund_type") ? json["additionnal_refund_type"] : [];
|
||||
privilegeStrategyEnum = json.containsKey("privilege_strategy") ? json["privilege_strategy"] : null;
|
||||
garantedDelaySecond = json.containsKey("garanted_delay") ? json["garanted_delay"] : null;
|
||||
exceeding = json.containsKey("exceeding") ? json["exceeding"] : false;
|
||||
exceedingRatio = json.containsKey("exceeding_ratio") ? json["exceeding_ratio"] : null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJSON() {
|
||||
return {
|
||||
"pricing": pricing?.serialize(),
|
||||
"refund_type": refundTypeEnum,
|
||||
"refund_ratio": refundRatio,
|
||||
"additionnal_refund_type": additionnalRefundTypeEnum,
|
||||
"privilege_strategy": privilegeStrategyEnum,
|
||||
"garanted_delay": garantedDelaySecond,
|
||||
"exceeding": exceeding,
|
||||
"exceeding_ratio": exceedingRatio,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class PricingStrategy extends SerializerDeserializer<PricingStrategy> {
|
||||
double? price;
|
||||
String? currency;
|
||||
int? buyingStrategyEnum;
|
||||
int? timeStrategyEnum;
|
||||
int? overrideStrategyEnum;
|
||||
|
||||
PricingStrategy({
|
||||
this.price,
|
||||
this.currency,
|
||||
this.buyingStrategyEnum,
|
||||
this.timeStrategyEnum,
|
||||
this.overrideStrategyEnum,
|
||||
});
|
||||
|
||||
@override
|
||||
PricingStrategy deserialize(dynamic json) {
|
||||
return PricingStrategy(
|
||||
price: json.containsKey("price") && json["price"] != null ? json["price"] : null,
|
||||
currency: json.containsKey("currency") && json["currency"] != null ? json["currency"] : null,
|
||||
buyingStrategyEnum: json.containsKey("buying_strategy") ? json["buying_strategy"] : null,
|
||||
timeStrategyEnum: json.containsKey("time_strategy") ? json["time_strategy"] : null,
|
||||
overrideStrategyEnum: json.containsKey("override_strategy") ? json["override_strategy"] : null,
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"price": price,
|
||||
"currency": currency,
|
||||
"buying_strategy": buyingStrategyEnum,
|
||||
"time_strategy": timeStrategyEnum,
|
||||
"override_strategy": overrideStrategyEnum,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
Type? getTopicType(String topic) {
|
||||
if (topic == "processing") { return ProcessingItem; }
|
||||
else if (topic == "data") { return DataItem; }
|
||||
else if (topic == "compute") { return ComputeItem; }
|
||||
else if (topic == "storage") { return StorageItem; }
|
||||
else if (topic == "workflow") { return WorkflowItem; }
|
||||
else { return null; }
|
||||
}
|
||||
|
||||
String getTopic(Type type) {
|
||||
if (type == AbstractItem) { return "resource"; }
|
||||
if (type == ProcessingItem) { return "processing"; }
|
||||
if (type == DataItem) { return "data"; }
|
||||
if (type == ComputeItem) { return "compute"; }
|
||||
if (type == StorageItem) { return "storage"; }
|
||||
if (type == WorkflowItem) { return "workflow"; }
|
||||
return "";
|
||||
}
|
||||
|
||||
bool isComputing(String topic) => topic == "processing";
|
||||
bool isData(String topic) => topic == "data";
|
||||
bool isCompute(String topic) => topic == "compute";
|
||||
bool isStorage(String topic) => topic == "storage";
|
||||
bool isWorkflow(String topic) => topic == "workflow";
|
||||
|
||||
Color getColor(String topic) => isData(topic) ? Colors.blue : isComputing(topic) ? Colors.green :
|
||||
isCompute(topic) ? Colors.orange : isStorage(topic) ? redColor : Colors.grey;
|
||||
166
lib/models/resources/storage.dart
Normal file
166
lib/models/resources/storage.dart
Normal file
@@ -0,0 +1,166 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/services/enum_service.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
|
||||
class StorageItem extends AbstractItem<StoragePricing, StoragePartnership, StorageInstance, StorageItem> {
|
||||
StorageItem({
|
||||
this.acronym,
|
||||
this.typeEnum,
|
||||
}): super();
|
||||
|
||||
@override String get topic => "storage";
|
||||
// special attributes
|
||||
String? acronym;
|
||||
int? typeEnum;
|
||||
|
||||
@override deserialize(dynamic data) {
|
||||
try { data = data as Map<String, dynamic>;
|
||||
} catch (e) { return StorageItem(); }
|
||||
var w = StorageItem(
|
||||
acronym: data.containsKey("acronym") && data["acronym"] != null ? data["acronym"] : null,
|
||||
typeEnum: data.containsKey("storage_type") && data["storage_type"] != null ? EnumService.get("storage/type", data["storage_type"]) : null,
|
||||
);
|
||||
w.mapFromJSON(data, StorageInstance());
|
||||
if (w.logo != null) { // get image dimensions
|
||||
var image = Image.network(w.logo!);
|
||||
image.image
|
||||
.resolve(const ImageConfiguration())
|
||||
.addListener(
|
||||
ImageStreamListener(
|
||||
(ImageInfo info, bool _) {
|
||||
w.width = info.image.width.toDouble();
|
||||
w.height = info.image.height.toDouble();
|
||||
}));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"acronym": acronym,
|
||||
"storage_type": EnumService.enums["storage/type"] != null
|
||||
&& EnumService.enums["storage/type"]!["$typeEnum"] != null ?
|
||||
EnumService.enums["storage/type"]!["$typeEnum"] : typeEnum,
|
||||
};
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var obj = infos();
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class StorageInstance extends AbstractInstance<StoragePricing, StoragePartnership> {
|
||||
String? source;
|
||||
bool local = false;
|
||||
String? securityLevel;
|
||||
int? storageSizeEnum;
|
||||
int? size;
|
||||
bool encryption = false;
|
||||
String? redundancy;
|
||||
String? throughput;
|
||||
|
||||
StorageInstance({
|
||||
this.source,
|
||||
this.local = false,
|
||||
this.securityLevel,
|
||||
this.storageSizeEnum,
|
||||
this.size,
|
||||
this.encryption = false,
|
||||
this.redundancy,
|
||||
this.throughput,
|
||||
}): super();
|
||||
|
||||
@override
|
||||
StorageInstance deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return StorageInstance(); }
|
||||
var w = StorageInstance(
|
||||
source: json.containsKey("source") && json["source"] != null ? json["source"] : null,
|
||||
local: json.containsKey("local") && json["local"] != null ? json["local"] : false,
|
||||
securityLevel: json.containsKey("security_level") && json["security_level"] != null ? json["security_level"] : null,
|
||||
storageSizeEnum: json.containsKey("size_type") ? EnumService.get("storage/size", json["size_type"]) : null,
|
||||
size: json.containsKey("size") && json["size"] != null ? json["size"] : null,
|
||||
encryption: json.containsKey("encryption") && json["encryption"] != null ? json["encryption"] : false,
|
||||
redundancy: json.containsKey("redundancy") && json["redundancy"] != null ? json["redundancy"] : null,
|
||||
throughput: json.containsKey("throughput") && json["throughput"] != null ? json["throughput"] : null,
|
||||
);
|
||||
w.mapFromJSON(json, StoragePartnership());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {
|
||||
"local": local,
|
||||
"security_level": securityLevel,
|
||||
"size_type": EnumService.enums["storage/size"] != null
|
||||
&& EnumService.enums["storage/size"]!["$storageSizeEnum"] != null ?
|
||||
EnumService.enums["storage/size"]!["$storageSizeEnum"] : storageSizeEnum,
|
||||
"size": size,
|
||||
"encryption": encryption,
|
||||
"redundancy": redundancy,
|
||||
"throughput": throughput,
|
||||
"inputs": toListJson(inputs),
|
||||
"outputs": toListJson(outputs),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
var obj = infos();
|
||||
obj["source"] = source;
|
||||
obj["size_type"] = storageSizeEnum;
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class StoragePartnership extends AbstractPartnerShip<StoragePricing> {
|
||||
double? maxSizeGBAllowed;
|
||||
bool onlyEncryptedAllowed = false;
|
||||
|
||||
StoragePartnership({
|
||||
this.maxSizeGBAllowed,
|
||||
this.onlyEncryptedAllowed = false,
|
||||
}): super();
|
||||
|
||||
@override
|
||||
StoragePartnership deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return StoragePartnership(); }
|
||||
var w = StoragePartnership(
|
||||
maxSizeGBAllowed: json.containsKey("allowed_gb") && json["allowed_gb"] != null ? json["allowed_gb"] : null,
|
||||
onlyEncryptedAllowed: json.containsKey("personal_data_allowed") && json["personal_data_allowed"] != null ? json["personal_data_allowed"] : false,
|
||||
);
|
||||
w.mapFromJSON(json, StoragePricing());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
Map<String, dynamic> obj = {
|
||||
"allowed_gb": maxSizeGBAllowed,
|
||||
"personal_data_allowed": onlyEncryptedAllowed,
|
||||
};
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class StoragePricing extends AbstractPricing {
|
||||
@override StoragePricing deserialize(json) {
|
||||
var w = StoragePricing();
|
||||
w.mapFromJSON(json);
|
||||
return w;
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return toJSON();
|
||||
}
|
||||
}
|
||||
101
lib/models/resources/workflow.dart
Normal file
101
lib/models/resources/workflow.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
|
||||
class WorkflowItem extends AbstractItem<WorkflowPricing, WorkflowPartnership, WorkflowInstance, WorkflowItem> {
|
||||
// special attributes
|
||||
String? workflowID;
|
||||
|
||||
WorkflowItem({
|
||||
this.workflowID,
|
||||
}): super();
|
||||
|
||||
@override String get topic => "workflow";
|
||||
|
||||
@override deserialize(dynamic data) {
|
||||
try { data = data as Map<String, dynamic>;
|
||||
} catch (e) { return WorkflowItem(); }
|
||||
var w = WorkflowItem(
|
||||
workflowID: data.containsKey("workflow_id") && data["workflow_id"] != null ? data["workflow_id"] : null,
|
||||
);
|
||||
w.mapFromJSON(data, WorkflowInstance());
|
||||
if (w.logo != null) { // get image dimensions
|
||||
var image = Image.network(w.logo!);
|
||||
image.image
|
||||
.resolve(const ImageConfiguration())
|
||||
.addListener(
|
||||
ImageStreamListener(
|
||||
(ImageInfo info, bool _) {
|
||||
w.width = info.image.width.toDouble();
|
||||
w.height = info.image.height.toDouble();
|
||||
}));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
Map<String, dynamic> obj ={
|
||||
"workflow_id": workflowID,
|
||||
};
|
||||
obj.addAll(toJSON());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class WorkflowInstance extends AbstractInstance<WorkflowPricing, WorkflowPartnership> {
|
||||
WorkflowInstance(): super();
|
||||
|
||||
@override
|
||||
WorkflowInstance deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return WorkflowInstance(); }
|
||||
var w = WorkflowInstance();
|
||||
w.mapFromJSON(json, WorkflowPartnership());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> infos() {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
class WorkflowPartnership extends AbstractPartnerShip<WorkflowPricing> {
|
||||
WorkflowPartnership(): super();
|
||||
|
||||
@override
|
||||
WorkflowPartnership deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return WorkflowPartnership(); }
|
||||
var w = WorkflowPartnership();
|
||||
w.mapFromJSON(json, WorkflowPricing());
|
||||
return w;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
class WorkflowPricing extends AbstractPricing {
|
||||
@override WorkflowPricing deserialize(json) {
|
||||
var w = WorkflowPricing();
|
||||
w.mapFromJSON(json);
|
||||
return w;
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() {
|
||||
return toJSON();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/logs.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/data.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/models/shared.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/models/workspace.dart';
|
||||
|
||||
Map<Type, SerializerDeserializer> refs = <Type, SerializerDeserializer> {
|
||||
@@ -7,17 +15,27 @@ Map<Type, SerializerDeserializer> refs = <Type, SerializerDeserializer> {
|
||||
Search: Search(),
|
||||
Workspace: Workspace(),
|
||||
DataItem: DataItem(),
|
||||
DataCenterItem: DataCenterItem(),
|
||||
ComputeItem: ComputeItem(),
|
||||
StorageItem: StorageItem(),
|
||||
ComputingItem: ComputingItem(),
|
||||
ProcessingItem: ProcessingItem(),
|
||||
Workflow: Workflow(),
|
||||
Resource: Resource(),
|
||||
WorkflowExecutions: WorkflowExecutions(),
|
||||
LogsResult: LogsResult(),
|
||||
Check: Check(),
|
||||
CollaborativeArea: CollaborativeArea(),
|
||||
SimpleData: SimpleData(),
|
||||
EnumData: EnumData(),
|
||||
};
|
||||
|
||||
class APIResponse<T extends SerializerDeserializer> {
|
||||
APIResponse({
|
||||
this.data,
|
||||
this.code = 200,
|
||||
this.error = "",
|
||||
this.offset = 0,
|
||||
});
|
||||
int code = 200;
|
||||
int offset = 0;
|
||||
T? data ;
|
||||
String? error = "";
|
||||
@@ -28,18 +46,69 @@ class APIResponse<T extends SerializerDeserializer> {
|
||||
}
|
||||
|
||||
APIResponse<T> deserialize(dynamic j) {
|
||||
dynamic data;
|
||||
try {
|
||||
if (j["data"] == null) { data = j; }
|
||||
else {
|
||||
data = j["data"];
|
||||
}
|
||||
} catch (e) { data = j; }
|
||||
try {
|
||||
return APIResponse<T>(
|
||||
data: refs[T]!.deserialize(j),
|
||||
data: refs[T]!.deserialize(data),
|
||||
code: j.containsKey("code") && j["code"] != null ? j["code"] : 200,
|
||||
error: j.containsKey("error") && j["error"] != null ? j["error"] : "",
|
||||
);
|
||||
} catch (e) { return APIResponse<T>( data: refs[T]!.deserialize(j), ); }
|
||||
|
||||
} catch (e) {
|
||||
return APIResponse<T>( data: refs[T]?.deserialize(data), );
|
||||
}
|
||||
}
|
||||
}
|
||||
class RawData extends SerializerDeserializer<RawData> {
|
||||
RawData({ this.values = const []});
|
||||
dynamic values;
|
||||
@override deserialize(dynamic json) { return RawData(values: json); }
|
||||
|
||||
class SimpleData extends SerializerDeserializer<SimpleData> {
|
||||
SimpleData({ this.value });
|
||||
dynamic value;
|
||||
@override deserialize(dynamic json) {
|
||||
return SimpleData(value: json);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => { };
|
||||
}
|
||||
|
||||
class EnumData extends SerializerDeserializer<EnumData> {
|
||||
EnumData({ this.value = const {} });
|
||||
Map<String, dynamic> value = {};
|
||||
@override deserialize(dynamic json) {
|
||||
return EnumData(value: json as Map<String, dynamic>);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => { };
|
||||
}
|
||||
|
||||
class RawData extends SerializerDeserializer<RawData> {
|
||||
RawData({ this.values = const []});
|
||||
List<dynamic> values = [];
|
||||
@override deserialize(dynamic json) {
|
||||
try {
|
||||
return RawData(values: json ?? []);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
print(json);
|
||||
return RawData();
|
||||
}
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => { };
|
||||
}
|
||||
|
||||
abstract class ShallowData {
|
||||
String getID();
|
||||
String getName();
|
||||
Map<String, dynamic> serialize();
|
||||
}
|
||||
|
||||
class Shallow {
|
||||
String id;
|
||||
String name;
|
||||
Shallow({
|
||||
this.id = "",
|
||||
this.name = "",
|
||||
});
|
||||
}
|
||||
37
lib/models/schedule.dart
Normal file
37
lib/models/schedule.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
|
||||
class Scheduler extends SerializerDeserializer<Scheduler> {
|
||||
DateTime? start;
|
||||
DateTime? end;
|
||||
double? duration;
|
||||
String? cron;
|
||||
|
||||
Scheduler({
|
||||
this.start,
|
||||
this.end,
|
||||
this.duration,
|
||||
this.cron,
|
||||
});
|
||||
|
||||
@override
|
||||
Scheduler deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Scheduler(); }
|
||||
var w = Scheduler(
|
||||
start: json.containsKey("start") && json["start"] != null ? DateTime.parse(json["start"]) : null,
|
||||
end: json.containsKey("end") && json["end"] != null ? DateTime.parse(json["end"]) : null,
|
||||
duration: json.containsKey("duration_s") && json["duration_s"] != null ? json["duration_s"] : -1,
|
||||
cron: json.containsKey("cron") && json["cron"] != null ? json["cron"] : null,
|
||||
);
|
||||
return w;
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"start": start?.toIso8601String(),
|
||||
"end": end?.toIso8601String(),
|
||||
"duration_s": duration,
|
||||
"cron": cron,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,381 +1,33 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/data.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
|
||||
const List<ComputingItem> _emptyComputing = [];
|
||||
const List<DataItem> _emptyData = [];
|
||||
const List<DataCenterItem> _emptyDataCenter = [];
|
||||
const List<StorageItem> _emptyStorage = [];
|
||||
class Search extends SerializerDeserializer<Search> {
|
||||
Search({
|
||||
this.computing = _emptyComputing,
|
||||
this.datacenter = _emptyDataCenter,
|
||||
this.data = _emptyData,
|
||||
this.storage = _emptyStorage,
|
||||
this.computing = const [],
|
||||
this.compute = const [],
|
||||
this.data = const [],
|
||||
this.storage = const [],
|
||||
});
|
||||
List<ComputingItem> computing;
|
||||
List<DataCenterItem> datacenter;
|
||||
List<ProcessingItem> computing;
|
||||
List<ComputeItem> compute;
|
||||
List<DataItem> data;
|
||||
List<StorageItem> storage;
|
||||
@override deserialize(dynamic json) {
|
||||
json = json as Map<String, dynamic>;
|
||||
return Search(
|
||||
computing: json.containsKey("computing") ? fromListJson(json["computing"], ComputingItem()) : [],
|
||||
datacenter: json.containsKey("datacenter") ? fromListJson(json["datacenter"], DataCenterItem()) : [],
|
||||
computing: json.containsKey("processing") ? fromListJson(json["processing"], ProcessingItem()) : [],
|
||||
compute: json.containsKey("compute") ? fromListJson(json["compute"], ComputeItem()) : [],
|
||||
data: json.containsKey("data") ? fromListJson(json["data"], DataItem()) : [],
|
||||
storage: json.containsKey("storage") ? fromListJson(json["storage"], StorageItem()) : [],
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"processing": toListJson<ProcessingItem>(computing),
|
||||
"compute": toListJson<ComputeItem>(compute),
|
||||
"data": toListJson<DataItem>(data),
|
||||
"storage": toListJson<StorageItem>(storage),
|
||||
};
|
||||
}
|
||||
const List<String> _empty = [];
|
||||
abstract class AbstractItem {
|
||||
String? id;
|
||||
String? name;
|
||||
String? logo;
|
||||
String? type;
|
||||
String? owner;
|
||||
String? description;
|
||||
String? shortDescription;
|
||||
String topic = "";
|
||||
}
|
||||
|
||||
Type? getTopicType(String topic) {
|
||||
if (topic == "computing") { return ComputingItem; }
|
||||
else if (topic == "data") { return DataItem; }
|
||||
else if (topic == "datacenter") { return DataCenterItem; }
|
||||
else if (topic == "storage") { return StorageItem; }
|
||||
else { return null; }
|
||||
}
|
||||
|
||||
String getTopic(Type type) {
|
||||
if (type == ComputingItem) { return "computing"; }
|
||||
if (type == DataItem) { return "data"; }
|
||||
if (type == DataCenterItem) { return "datacenter"; }
|
||||
if (type == StorageItem) { return "storage"; }
|
||||
return "";
|
||||
}
|
||||
|
||||
bool isComputing(String topic) => topic == "computing";
|
||||
bool isData(String topic) => topic == "data";
|
||||
bool isDataCenter(String topic) => topic == "datacenter";
|
||||
bool isStorage(String topic) => topic == "storage";
|
||||
|
||||
class ComputingItem extends SerializerDeserializer<ComputingItem> implements AbstractItem {
|
||||
ComputingItem({
|
||||
this.id,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.owner,
|
||||
this.price,
|
||||
this.image,
|
||||
this.command,
|
||||
this.licence,
|
||||
this.description,
|
||||
this.requirements,
|
||||
this.ports = _empty,
|
||||
this.shortDescription,
|
||||
this.dinputs = _empty,
|
||||
this.doutputs = _empty,
|
||||
this.arguments = _empty,
|
||||
this.environment = _empty,
|
||||
});
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String? owner;
|
||||
@override String topic = "computing";
|
||||
double? price;
|
||||
String? image;
|
||||
String? command;
|
||||
String? licence;
|
||||
List<dynamic> ports;
|
||||
List<dynamic> dinputs;
|
||||
List<dynamic> doutputs;
|
||||
List<dynamic> arguments;
|
||||
@override String? description;
|
||||
@override String? shortDescription;
|
||||
List<dynamic> environment;
|
||||
ExecRequirements? requirements;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ComputingItem(); }
|
||||
return ComputingItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
|
||||
image: json.containsKey("image") ? json["image"] : null,
|
||||
command: json.containsKey("command") ? json["command"] : null,
|
||||
licence: json.containsKey("licence") ? json["licence"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
ports: json["ports"] ?? [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
dinputs: json["dinputs"] ?? [],
|
||||
doutputs: json["doutputs"] ?? [],
|
||||
arguments: json["arguments"] ?? [],
|
||||
environment: json["environment"] ?? [],
|
||||
requirements: json.containsKey("requirements") ? ExecRequirements().deserialize(json["execution_requirements"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
|
||||
class ExecRequirements extends SerializerDeserializer<ExecRequirements> {
|
||||
ExecRequirements({
|
||||
this.ram,
|
||||
this.cpus,
|
||||
this.gpus,
|
||||
this.diskIO,
|
||||
this.scallingModel,
|
||||
this.parallel = false,
|
||||
});
|
||||
double? ram;
|
||||
double? cpus;
|
||||
double? gpus;
|
||||
String? diskIO;
|
||||
bool parallel = false;
|
||||
double? scallingModel;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ExecRequirements(); }
|
||||
return ExecRequirements(
|
||||
ram: json.containsKey("ram") ? json["ram"]?.toDouble() : null,
|
||||
cpus: json.containsKey("cpus") ? json["cpus"]?.toDouble() : null,
|
||||
gpus: json.containsKey("gpus") ? json["gpus"]?.toDouble() : null,
|
||||
diskIO: json.containsKey("disk_io") ? json["disk_io"] : null,
|
||||
scallingModel: json.containsKey("scaling_model") ? json["scaling_model"]?.toDouble() : null,
|
||||
parallel: json.containsKey("parallel") ? json["parallel"] : false,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
|
||||
class DataItem extends SerializerDeserializer<DataItem> implements AbstractItem {
|
||||
DataItem({
|
||||
this.id,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.dtype,
|
||||
this.owner,
|
||||
this.example,
|
||||
this.location,
|
||||
this.description,
|
||||
this.protocol = _empty,
|
||||
this.shortDescription,
|
||||
});
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String topic = "data";
|
||||
String? dtype;
|
||||
String? example;
|
||||
String? location;
|
||||
@override String? description;
|
||||
List<dynamic> protocol;
|
||||
@override String? shortDescription;
|
||||
@override String? owner;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return DataItem(); }
|
||||
return DataItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
dtype: json.containsKey("dtype") ? json["dtype"] : null,
|
||||
example: json.containsKey("example") ? json["example"] : null,
|
||||
location: json.containsKey("location") ? json["location"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
protocol: json["protocol"] ?? [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
const List<GPU> _emptyGPU = [];
|
||||
class DataCenterItem extends SerializerDeserializer<DataCenterItem> implements AbstractItem {
|
||||
DataCenterItem({
|
||||
this.id,
|
||||
this.cpu,
|
||||
this.ram,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.owner,
|
||||
this.acronym,
|
||||
this.bookingPrice,
|
||||
this.description,
|
||||
this.hosts = _empty,
|
||||
this.gpus = _emptyGPU,
|
||||
this.shortDescription,
|
||||
});
|
||||
CPU? cpu;
|
||||
RAM? ram;
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String? owner;
|
||||
@override String topic = "datacenter";
|
||||
String? acronym;
|
||||
List<GPU> gpus = [];
|
||||
@override String? description;
|
||||
List<dynamic> hosts;
|
||||
double? bookingPrice;
|
||||
@override String? shortDescription;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return DataCenterItem(); }
|
||||
return DataCenterItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null,
|
||||
cpu: json.containsKey("cpu") ? CPU().deserialize(json["cpu"]) : null,
|
||||
acronym: json.containsKey("acronym") ? json["acronym"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
bookingPrice: json.containsKey("bookingPrice") ? json["bookingPrice"]?.toDouble() : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
hosts: json["hosts"] ?? [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
gpus: json.containsKey("gpus") ? fromListJson(json["gpus"] ?? [], GPU()) : [],
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
class CPU extends SerializerDeserializer<CPU> {
|
||||
CPU({
|
||||
this.cores,
|
||||
this.platform,
|
||||
this.architecture,
|
||||
this.minimumMemory,
|
||||
this.shared = false,
|
||||
});
|
||||
double? cores;
|
||||
String? platform;
|
||||
bool shared = false;
|
||||
String? architecture;
|
||||
double? minimumMemory;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return CPU(); }
|
||||
return CPU(
|
||||
cores: json.containsKey("cores") ? json["cores"]?.toDouble() : null,
|
||||
platform: json.containsKey("platform") ? json["platform"] : null,
|
||||
architecture: json.containsKey("architecture") ? json["architecture"] : null,
|
||||
minimumMemory: json.containsKey("minimumMemory") ? json["minimumMemory"]?.toDouble() : null,
|
||||
shared: json.containsKey("shared") ? json["shared"] : false,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
class GPU extends SerializerDeserializer<GPU> {
|
||||
GPU({
|
||||
this.cudaCores,
|
||||
this.memory,
|
||||
this.model,
|
||||
this.tensorCores,
|
||||
});
|
||||
double? cudaCores;
|
||||
double? memory;
|
||||
String? model;
|
||||
double? tensorCores;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return GPU(); }
|
||||
return GPU(
|
||||
cudaCores: json.containsKey("cuda_cores") ? json["cuda_cores"]?.toDouble() : null,
|
||||
memory: json.containsKey("memory") ? json["memory"]?.toDouble() : null,
|
||||
model: json.containsKey("model") ? json["model"] : null,
|
||||
tensorCores: json.containsKey("tensor_cores") ? json["tensor_cores"]?.toDouble() : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
class RAM extends SerializerDeserializer<RAM> {
|
||||
RAM({
|
||||
this.ecc = false,
|
||||
this.size,
|
||||
});
|
||||
bool ecc = false;
|
||||
double? size;
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return RAM(); }
|
||||
return RAM(
|
||||
ecc: json.containsKey("ecc") ? json["ecc"] : false,
|
||||
size: json.containsKey("size") ? json["size"]?.toDouble() : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
class StorageItem extends SerializerDeserializer<StorageItem> implements AbstractItem {
|
||||
StorageItem({
|
||||
this.id,
|
||||
this.url,
|
||||
this.size,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.owner,
|
||||
this.acronym,
|
||||
this.throughput,
|
||||
this.redundancy,
|
||||
this.description,
|
||||
this.bookingPrice,
|
||||
this.shortDescription,
|
||||
this.encryption = false,
|
||||
});
|
||||
@override String? id;
|
||||
String? url;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String topic = "storage";
|
||||
double? size;
|
||||
@override String? owner;
|
||||
String? acronym;
|
||||
String? redundancy;
|
||||
String? throughput;
|
||||
@override String? description;
|
||||
double? bookingPrice;
|
||||
bool encryption = false;
|
||||
@override String? shortDescription;
|
||||
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return StorageItem(); }
|
||||
return StorageItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
url: json.containsKey("URL") ? json["URL"] : null,
|
||||
size: json.containsKey("size") ? json["size"]?.toDouble() : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
acronym: json.containsKey("DCacronym") ? json["DCacronym"] : null,
|
||||
bookingPrice: json.containsKey("bookingPrice") ? json["bookingPrice"]?.toDouble() : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
throughput: json.containsKey("throughput") ? json["throughput"] : [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
redundancy: json.containsKey("redundancy") ? json["redundancy"] : [],
|
||||
encryption: json.containsKey("encryption") ? json["encryption"] : false,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
}
|
||||
161
lib/models/shared.dart
Normal file
161
lib/models/shared.dart
Normal file
@@ -0,0 +1,161 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/models/workspace.dart';
|
||||
|
||||
/*
|
||||
based on :
|
||||
type CollaborativeAreaRule struct {
|
||||
ShareMode string `json:"share_mode,omitempty" bson:"share_mode,omitempty"` // Share is the share of the rule
|
||||
CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` // CreatedAt is the time the rule was created
|
||||
Creator string `json:"creator,omitempty" bson:"creator,omitempty"` // Creator is the creator of the rule
|
||||
ExploitedBy string `json:"exploited_by,omitempty" bson:"exploited_by,omitempty"` // ExploitedBy is the exploited by of the rule
|
||||
}
|
||||
*/
|
||||
class CollaborativeAreaRule extends SerializerDeserializer<CollaborativeAreaRule> {
|
||||
String? shareMode;
|
||||
DateTime? createdAt;
|
||||
String? creator;
|
||||
String? exploitedBy;
|
||||
|
||||
CollaborativeAreaRule(
|
||||
{this.shareMode,
|
||||
this.createdAt,
|
||||
this.creator,
|
||||
this.exploitedBy,});
|
||||
|
||||
@override
|
||||
CollaborativeAreaRule deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return CollaborativeAreaRule(); }
|
||||
return CollaborativeAreaRule(
|
||||
shareMode: json.containsKey("share_mode") ? json["share_mode"] : null,
|
||||
createdAt: json.containsKey("created_at") ? DateTime.parse(json["created_at"]) : null,
|
||||
creator: json.containsKey("creator") ? json["creator"] : null,
|
||||
exploitedBy: json.containsKey("exploited_by") ? json["exploited_by"] : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> serialize() => {
|
||||
"share_mode": shareMode,
|
||||
"created_at": createdAt?.toIso8601String(),
|
||||
"creator": creator,
|
||||
"exploited_by": exploitedBy,
|
||||
};
|
||||
}
|
||||
|
||||
class CollaborativeArea extends SerializerDeserializer<CollaborativeArea> {
|
||||
String? id;
|
||||
String? name;
|
||||
String? description;
|
||||
String? creatorID;
|
||||
String? version;
|
||||
Map<String, dynamic> attributes = {};
|
||||
List<Workspace> workspaces = [];
|
||||
List<Workflow> workflows = [];
|
||||
List<Peer> peers = [];
|
||||
List<dynamic> rules = [];
|
||||
CollaborativeAreaRule? rule;
|
||||
|
||||
CollaborativeArea(
|
||||
{this.id,
|
||||
this.name,
|
||||
this.description,
|
||||
this.creatorID,
|
||||
this.version,
|
||||
this.attributes = const {},
|
||||
this.workspaces = const [],
|
||||
this.workflows = const [],
|
||||
this.peers = const [],
|
||||
this.rule,
|
||||
this.rules = const []});
|
||||
|
||||
@override
|
||||
deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return CollaborativeArea(); }
|
||||
return CollaborativeArea(
|
||||
rule : json.containsKey("collaborative_area") ? CollaborativeAreaRule().deserialize(json["collaborative_area"]) : CollaborativeAreaRule(),
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
creatorID: json.containsKey("creator_id") ? json["creator_id"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
version: json.containsKey("version") ? json["version"] : null,
|
||||
attributes: json.containsKey("attributes") ? json["attributes"] : {},
|
||||
workspaces: json.containsKey("shared_workspaces") && json["shared_workspaces"] != null ? fromListJson(json["shared_workspaces"], Workspace()) : [],
|
||||
workflows: json.containsKey("shared_workflows") && json["shared_workflows"] != null ? fromListJson(json["shared_workflows"], Workflow()) : [],
|
||||
peers: json.containsKey("shared_peers") && json["shared_peers"] != null ? fromListJson(json["shared_peers"], Peer()) : [],
|
||||
rules: json.containsKey("shared_rules") && json["shared_rules"] != null ? json["shared_rules"] : [],
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"description": description,
|
||||
"creator_id": creatorID,
|
||||
"version": version,
|
||||
"attributes": attributes,
|
||||
"rule": rule?.serialize(),
|
||||
"workspaces": workspaces.map((e) => e.id).toList(),
|
||||
"workflows": workflows.map((e) => e.id).toList(),
|
||||
"peers": peers.map((e) => e.id).toList(),
|
||||
"rules": rules.map((e) => e.id).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
class Rule extends SerializerDeserializer<Rule> {
|
||||
String? id;
|
||||
String? name;
|
||||
String? description;
|
||||
|
||||
Rule(
|
||||
{this.id,
|
||||
this.name,
|
||||
this.description,});
|
||||
|
||||
@override
|
||||
deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Rule(); }
|
||||
return Rule(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"description": description,
|
||||
};
|
||||
}
|
||||
|
||||
class Peer extends SerializerDeserializer<Peer> implements ShallowData {
|
||||
String? id;
|
||||
String? name;
|
||||
|
||||
Peer(
|
||||
{this.id,
|
||||
this.name,});
|
||||
|
||||
@override String getID() => id ?? "";
|
||||
@override String getName() => name ?? "";
|
||||
|
||||
@override
|
||||
deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Peer(); }
|
||||
return Peer(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
};
|
||||
}
|
||||
818
lib/models/workflow.dart
Normal file
818
lib/models/workflow.dart
Normal file
@@ -0,0 +1,818 @@
|
||||
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/models/abstract.dart';
|
||||
import 'package:oc_front/models/logs.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/data.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
import 'package:oc_front/models/resources/workflow.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/widgets/forms/sub_keys_forms.dart';
|
||||
|
||||
class Check extends SerializerDeserializer<Check> {
|
||||
bool isAvailable = false;
|
||||
|
||||
Check({
|
||||
this.isAvailable = false,
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Check(); }
|
||||
return Check(
|
||||
isAvailable: json.containsKey("is_available") ? json["is_available"] : false,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"is_available": isAvailable,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class WorkflowExecutions extends SerializerDeserializer<WorkflowExecutions> {
|
||||
List<WorkflowExecution> executions = [];
|
||||
|
||||
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? startDate;
|
||||
String? endDate;
|
||||
int? status;
|
||||
String? workflowId;
|
||||
|
||||
List<Log>? logs;
|
||||
|
||||
|
||||
WorkflowExecution({
|
||||
this.id,
|
||||
this.startDate,
|
||||
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"] : "",
|
||||
startDate: json.containsKey("execution_date") ? json["execution_date"] : "",
|
||||
status: json.containsKey("state") ? json["state"] : 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": startDate,
|
||||
"status": status,
|
||||
"workflow_id": workflowId,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Workflow extends SerializerDeserializer<Workflow> implements ShallowData {
|
||||
String? id;
|
||||
String? name;
|
||||
List<dynamic> data;
|
||||
List<dynamic> compute;
|
||||
List<dynamic> storage;
|
||||
List<dynamic> processing;
|
||||
List<dynamic> workflows;
|
||||
Graph? graph;
|
||||
List<dynamic> shared;
|
||||
|
||||
Workflow({
|
||||
this.id,
|
||||
this.name = "",
|
||||
this.data = const [],
|
||||
this.compute = const [],
|
||||
this.storage = const [],
|
||||
this.processing = const [],
|
||||
this.workflows = const [],
|
||||
this.graph,
|
||||
this.shared = const [],
|
||||
});
|
||||
|
||||
@override String getID() => id ?? "";
|
||||
@override String getName() => name ?? "";
|
||||
String getDescription() => "";
|
||||
|
||||
@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"] : [],
|
||||
compute: json.containsKey("computes") ? json["computes"] : [],
|
||||
data: json.containsKey("datas") ? json["datas"] : [],
|
||||
storage: json.containsKey("storages") ? json["storages"] : [],
|
||||
shared: json.containsKey("shared") ? json["shared"] : [],
|
||||
graph: json.containsKey("graph") ? Graph().deserialize(json["graph"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var obj = {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"datas": data,
|
||||
"storages": storage,
|
||||
"computes" : compute,
|
||||
"workflows": workflows,
|
||||
"processings": processing,
|
||||
};
|
||||
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"]);
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> toDashboard() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"shared": shared,
|
||||
"graph": graph?.toDashboard(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Scheduler extends SerializerDeserializer<Scheduler> {
|
||||
String? id;
|
||||
String? name;
|
||||
String? cron;
|
||||
DateTime? start;
|
||||
DateTime? end;
|
||||
int? mode;
|
||||
|
||||
Scheduler({
|
||||
this.id,
|
||||
this.name,
|
||||
this.cron,
|
||||
this.start,
|
||||
this.end,
|
||||
this.mode,
|
||||
});
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
id = j["id"];
|
||||
name = j["name"];
|
||||
cron = j["cron"];
|
||||
mode =j["mode"];
|
||||
try {
|
||||
start = j["start"] != null ? DateTime.parse(j["start"]) : DateTime.now().add( const Duration(minutes: 1)).toUtc();
|
||||
if (start == DateTime.utc(0)) {
|
||||
start = DateTime.now().add( const Duration(minutes: 1)).toUtc();
|
||||
}
|
||||
if (j.containsKey("end") && j["end"] != null) {
|
||||
end = DateTime.parse(j["end"]);
|
||||
}
|
||||
|
||||
} catch (e) { /**/ }
|
||||
}
|
||||
Map<String, dynamic> toDashboard() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"cron": cron,
|
||||
"mode": mode ?? 1,
|
||||
"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"] : "",
|
||||
mode: json.containsKey("mode") ? json["mode"] : "",
|
||||
start: json.containsKey("start") && json["start"] != null ? DateTime.parse(json["start"]) : null,
|
||||
end: json.containsKey("end") && json["end"] != null ? DateTime.parse(json["end"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
try {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"cron": cron ?? "",
|
||||
"mode": mode ?? 1,
|
||||
"start": start?.toIso8601String(),
|
||||
"end": end?.toIso8601String(),
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
"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 [],
|
||||
});
|
||||
|
||||
Map<String, List<dynamic>> getInfosToUpdate(SubMapFormsType type) {
|
||||
Map<String, List<dynamic>> infos = {};
|
||||
for (var item in items.values) {
|
||||
var inst = item.getElement()?.getSelectedInstance();
|
||||
if (inst == null) { return infos; }
|
||||
infos[item.id ?? ""] = (type == SubMapFormsType.INPUT ? inst.inputs : (
|
||||
type == SubMapFormsType.OUTPUT ? inst.outputs : inst.env)).map( (e) => e.serialize()).toList();
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
Map<String, List<dynamic>> getEnvToUpdate() {
|
||||
return getInfosToUpdate(SubMapFormsType.ENV);
|
||||
}
|
||||
|
||||
Map<String, List<dynamic>> getInputToUpdate() {
|
||||
return getInfosToUpdate(SubMapFormsType.INPUT);
|
||||
}
|
||||
|
||||
Map<String, List<dynamic>> getOutputToUpdate() {
|
||||
return getInfosToUpdate(SubMapFormsType.OUTPUT);
|
||||
}
|
||||
|
||||
|
||||
GraphItem getItemByElementID(String id) {
|
||||
return items[id] ?? GraphItem();
|
||||
}
|
||||
Map<String,GraphItem?> getArrowByElementID(String id) {
|
||||
Map<String,GraphItem?> arr = {};
|
||||
for (var link in links) {
|
||||
var nested = false;
|
||||
var reverse = false;
|
||||
String? from = link.source?.id;
|
||||
String? to = link.destination?.id;
|
||||
bool isInLink = (from?.contains(id) ?? false) || (to?.contains(id) ?? false);
|
||||
if (isInLink && (["storage", "compute"].contains(getItemByElementID(from ?? "").getElement()?.getType())
|
||||
|| ["storage", "compute"].contains(getItemByElementID(to ?? "").getElement()?.getType()))) {
|
||||
nested = true;
|
||||
reverse = link.source?.id?.contains(id) ?? false;
|
||||
}
|
||||
if (nested || isInLink) {
|
||||
arr[reverse ? (to ?? "") : (from ?? "") ] = getItemByElementID(reverse ? (to ?? "") : (from ?? "") );
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
void fillEnv(AbstractItem? mainItem, GraphItem? item, SubMapFormsType type, Map<String,int> alreadySeen) {
|
||||
if (mainItem == null || item == null) {
|
||||
return;
|
||||
}
|
||||
AbstractItem? el = item.getElement();
|
||||
if (el?.getSelectedInstance() == null) {
|
||||
return;
|
||||
}
|
||||
var inst = el!.getSelectedInstance()!;
|
||||
|
||||
var inst2 = mainItem.getSelectedInstance()!;
|
||||
var what = type == SubMapFormsType.INPUT ? inst.inputs : (
|
||||
type == SubMapFormsType.OUTPUT ? inst.outputs : inst.env);
|
||||
var what2 = type == SubMapFormsType.INPUT ? inst2.inputs : (
|
||||
type == SubMapFormsType.OUTPUT ? inst2.outputs : inst2.env);
|
||||
for (var e in what2) {
|
||||
if (e.attr != null && e.value == null) {
|
||||
e.value = inst2.serialize()[e.attr!];
|
||||
}
|
||||
}
|
||||
// should find arrow env info and add it to the env
|
||||
List<Param> extParams = [];
|
||||
var arrows = links.where( (e) => (e.source?.id?.contains(item.id ?? "") ?? false) || (e.destination?.id?.contains(item.id ?? "") ?? false));
|
||||
for (var arrow in arrows) {
|
||||
for (var info in arrow.infos) {
|
||||
var i = info as Map<String, dynamic>;
|
||||
for (var entry in i.entries) {
|
||||
if (entry.value == null) { continue; }
|
||||
|
||||
var varName = "LINK_${el.getName().toUpperCase().replaceAll(" ", "_")}_${entry.key.toUpperCase()}";
|
||||
/*alreadySeen[varName] = (alreadySeen[varName] ?? -1) + 1;
|
||||
if ((alreadySeen[varName] ?? 0) > 1) {
|
||||
varName = "${varName}_${alreadySeen[varName]}";
|
||||
}*/
|
||||
if ((entry.value is String) && !isEnvAttr(entry.value, what2)) {
|
||||
extParams.add(Param( name: varName,
|
||||
attr: entry.key, value: entry.value, origin: item.id, readOnly: true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( var param in what) {
|
||||
if (param.attr == null) { continue; }
|
||||
var varName = param.name != null && (param.name!.contains("LINK_")
|
||||
|| param.name!.contains("DATA_")
|
||||
|| param.name!.contains("PROCESSING_")
|
||||
|| param.name!.contains("STORAGE_")
|
||||
|| param.name!.contains("WORKFLOW_")
|
||||
|| param.name!.contains("COMPUTE") ) ? param.name : "${el.topic.toUpperCase()}_${el.getName().toUpperCase().replaceAll(" ", "_")}_${param.attr!.toUpperCase()}";
|
||||
/*alreadySeen[varName] = (alreadySeen[varName] ?? -1) + 1;
|
||||
if ((alreadySeen[varName] ?? 0) > 0) {
|
||||
varName = "${varName}_${alreadySeen[varName]}";
|
||||
}*/
|
||||
dynamic env;
|
||||
if (param.value == null) {
|
||||
var s = el.serialize();
|
||||
s.addAll(el.getSelectedInstance()?.serialize() ?? {});
|
||||
env = s[param.attr!];
|
||||
} else {
|
||||
env = param.value;
|
||||
}
|
||||
// bool isSrc = param.origin == null;
|
||||
//if (isSrc) { continue; }
|
||||
if (!isEnvAttr(env, what2)) {
|
||||
extParams.add(Param( name: varName,
|
||||
attr: param.attr, value: env, origin: item.id, readOnly: true));
|
||||
}
|
||||
}
|
||||
for (var param in extParams) {
|
||||
what2.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
bool isEnvAttr(String value, List<Param> params) {
|
||||
for (var e in params) {
|
||||
if (value == e.value) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void fill() {
|
||||
Map<String, int> alreadySeen = {};
|
||||
var its = items.values.toList();
|
||||
for (var type in [SubMapFormsType.INPUT, SubMapFormsType.OUTPUT, SubMapFormsType.ENV]) {
|
||||
for (var item in its) {
|
||||
var envs = type == SubMapFormsType.INPUT ? item.getElement()?.getSelectedInstance()?.inputs : (
|
||||
type == SubMapFormsType.OUTPUT ? item.getElement()?.getSelectedInstance()?.outputs : item.getElement()?.getSelectedInstance()?.env);
|
||||
if (envs != null) {
|
||||
envs.removeWhere( (e) => e.readOnly && e.name != null
|
||||
&& (e.name!.contains("LINK_")
|
||||
|| e.name!.contains("DATA_")
|
||||
|| e.name!.contains("PROCESSING_")
|
||||
|| e.name!.contains("STORAGE_")
|
||||
|| e.name!.contains("WORKFLOW_")
|
||||
|| e.name!.contains("COMPUTE") ));
|
||||
}
|
||||
}
|
||||
for (var item in [...its, ...its.reversed]) {
|
||||
var itss = getArrowByElementID(item.id ?? "");
|
||||
for (var i in itss.values) {
|
||||
fillEnv(item.getElement(), i, type, alreadySeen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
fill();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDashboard() {
|
||||
fill();
|
||||
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(); }
|
||||
var g = 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()) : {},
|
||||
);
|
||||
g.fill();
|
||||
return g;
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
fill();
|
||||
return {
|
||||
"zoom": zoom,
|
||||
"items": toMapJson(items),
|
||||
"links": toListJson(links),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class StorageProcessingGraphLink extends SerializerDeserializer<StorageProcessingGraphLink> {
|
||||
bool write = false;
|
||||
String? source;
|
||||
String? destination;
|
||||
String? filename;
|
||||
|
||||
StorageProcessingGraphLink({
|
||||
this.write = false,
|
||||
this.source,
|
||||
this.destination,
|
||||
this.filename,
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return StorageProcessingGraphLink(); }
|
||||
return StorageProcessingGraphLink(
|
||||
write: json.containsKey("write") ? json["write"] : false,
|
||||
source: json.containsKey("source") ? json["source"] : "",
|
||||
destination: json.containsKey("destination") ? json["destination"] : "",
|
||||
filename: json.containsKey("filename") && json["filename"] != null ? json["filename"] : "",
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"write": write,
|
||||
"source": source,
|
||||
"destination": destination,
|
||||
"filename": filename,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class GraphLink extends SerializerDeserializer<GraphLink> {
|
||||
Position? source;
|
||||
Position? destination;
|
||||
GraphLinkStyle? style;
|
||||
List<StorageProcessingGraphLink> infos = [];
|
||||
List<Param> env = [];
|
||||
|
||||
GraphLink({
|
||||
this.source,
|
||||
this.destination,
|
||||
this.style,
|
||||
this.infos = const [],
|
||||
this.env = const [],
|
||||
});
|
||||
|
||||
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"]);
|
||||
infos = fromListJson(j["infos"], StorageProcessingGraphLink());
|
||||
env = fromListJson(j["env"], Param());
|
||||
}
|
||||
|
||||
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(),
|
||||
"infos": toListJson(infos),
|
||||
"env": env.map( (el) => el.serialize()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return GraphLink(); }
|
||||
return GraphLink(
|
||||
source: json.containsKey("source") && json["source"] != null ? Position().deserialize(json["source"]) : null,
|
||||
destination: json.containsKey("destination") && json["destination"] != null ? Position().deserialize(json["destination"]) : null,
|
||||
style: json.containsKey("style") && json["style"] != null ? GraphLinkStyle().deserialize(json["style"]) : null,
|
||||
infos: json.containsKey("storage_link_infos") && json["storage_link_infos"] != null ? fromListJson(json["storage_link_infos"], StorageProcessingGraphLink()) : [],
|
||||
env: json.containsKey("env") && json["env"] != null ? fromListJson(json["env"], Param()) : [],
|
||||
);
|
||||
}
|
||||
@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();
|
||||
}
|
||||
obj["storage_link_infos"] = toListJson(infos);
|
||||
obj["env"] = toListJson(env);
|
||||
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;
|
||||
ComputeItem? compute;
|
||||
WorkflowItem? workflow;
|
||||
|
||||
GraphItem({
|
||||
this.id,
|
||||
this.width,
|
||||
this.height,
|
||||
this.position,
|
||||
this.data,
|
||||
this.processing,
|
||||
this.storage,
|
||||
this.compute,
|
||||
this.workflow,
|
||||
});
|
||||
|
||||
AbstractItem? getElement() {
|
||||
if (data != null) { return data!; }
|
||||
if (processing != null) { return processing!; }
|
||||
if (storage != null) { return storage!; }
|
||||
if (compute != null) { return compute!; }
|
||||
if (workflow != null) { return workflow!; }
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
id = j["id"];
|
||||
position = Position(x: j["x"], y: j["y"]);
|
||||
width = j["width"];
|
||||
height = j["height"];
|
||||
|
||||
if (j["element"] != null) {
|
||||
if (j["element"]["type"] == "data") { data = DataItem().deserialize(j["element"]);
|
||||
} else if (j["element"]["type"] == "processing") { processing = ProcessingItem().deserialize(j["element"]);
|
||||
} else if (j["element"]["type"] == "compute") { compute = ComputeItem().deserialize(j["element"]);
|
||||
} else if (j["element"]["type"] == "storage") { storage = StorageItem().deserialize(j["element"]);
|
||||
} else if (j["element"]["type"] == "workflow") { workflow = WorkflowItem().deserialize(j["element"]);
|
||||
} else {
|
||||
compute = null;
|
||||
data = null;
|
||||
processing = null;
|
||||
storage = null;
|
||||
workflow = null;
|
||||
}
|
||||
} else {
|
||||
compute = null;
|
||||
data = null;
|
||||
processing = null;
|
||||
storage = null;
|
||||
workflow = null;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDashboard() {
|
||||
Map<String, dynamic> element = {};
|
||||
List<AbstractItem?> items = [data, processing, storage, compute, workflow];
|
||||
for(var el in items) {
|
||||
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,
|
||||
compute: json.containsKey("compute") ? ComputeItem().deserialize(json["compute"]) : 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(),
|
||||
"compute": compute?.serialize(),
|
||||
"workflow": workflow?.serialize(),
|
||||
"position": position?.serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Position extends SerializerDeserializer<Position> {
|
||||
String? id;
|
||||
double? x;
|
||||
double? y;
|
||||
|
||||
Position({
|
||||
this.id,
|
||||
this.x,
|
||||
this.y,
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Position(); }
|
||||
return Position(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
x: json.containsKey("x") ? double.parse(json["x"].toString()) : null,
|
||||
y: json.containsKey("y") ? double.parse(json["y"].toString()) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"x": x ,
|
||||
"y": y,
|
||||
};
|
||||
}
|
||||
@@ -1,29 +1,61 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/data.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
import 'package:oc_front/models/resources/workflow.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
|
||||
class Workspace extends SerializerDeserializer<Workspace> {
|
||||
class Workspace extends SerializerDeserializer<Workspace> implements ShallowData {
|
||||
String? id;
|
||||
List<dynamic> data;
|
||||
List<dynamic> datacenter;
|
||||
List<dynamic> storage;
|
||||
List<dynamic> computing;
|
||||
String? name;
|
||||
bool? active;
|
||||
List<DataItem> datas;
|
||||
List<ComputeItem> computes;
|
||||
List<StorageItem> storages;
|
||||
List<ProcessingItem> processings;
|
||||
List<WorkflowItem> workflows;
|
||||
String? shared;
|
||||
|
||||
Workspace({
|
||||
this.id,
|
||||
this.computing = const [],
|
||||
this.data = const [],
|
||||
this.datacenter = const [],
|
||||
this.storage = const [],
|
||||
this.name,
|
||||
this.active = false,
|
||||
this.workflows = const [],
|
||||
this.datas = const [],
|
||||
this.computes = const [],
|
||||
this.storages = const [],
|
||||
this.processings = const [],
|
||||
this.shared,
|
||||
});
|
||||
|
||||
@override String getID() => id ?? "";
|
||||
@override String getName() => name ?? "";
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Workspace(); }
|
||||
return Workspace(
|
||||
computing: json.containsKey("computing") ? json["computing"] : [],
|
||||
datacenter: json.containsKey("datacenter") ? json["datacenter"] : [],
|
||||
data: json.containsKey("data") ? json["data"] : [],
|
||||
storage: json.containsKey("storage") ? json["storage"] : [],
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
shared: json["shared"],
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
active: json.containsKey("active") ? json["active"] : false,
|
||||
processings: json.containsKey("processing_resources") ? fromListJson(json["processing_resources"], ProcessingItem()) : [],
|
||||
storages: json.containsKey("storage_resources") ? fromListJson(json["storage_resources"], StorageItem()) : [],
|
||||
computes: json.containsKey("compute_resources") ? fromListJson(json["compute_resources"], ComputeItem()) : [],
|
||||
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() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"processings": processings.map((e) => e.id).toList(),
|
||||
"storages": storages.map((e) => e.id).toList(),
|
||||
"computes": computes.map((e) => e.id).toList(),
|
||||
"datas": datas.map((e) => e.id).toList(),
|
||||
"workflows": workflows.map((e) => e.id).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
abstract class AbstractFactory {
|
||||
GlobalKey getKey();
|
||||
Widget factory(GoRouterState state, List<String> args);
|
||||
bool searchFill();
|
||||
void search(BuildContext context);
|
||||
void search(BuildContext context, bool special);
|
||||
String? getSearch();
|
||||
void back(BuildContext context);
|
||||
}
|
||||
@@ -1,41 +1,103 @@
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/widgets/catalog.dart';
|
||||
import 'package:localstorage/localstorage.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/core/sections/header/search.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/search_service.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/resource_service.dart';
|
||||
|
||||
|
||||
class CatalogFactory implements AbstractFactory {
|
||||
static List<AbstractItem> items = [];
|
||||
@override GlobalKey getKey() { return key; }
|
||||
static GlobalKey<CatalogPageWidgetState> key = GlobalKey<CatalogPageWidgetState>();
|
||||
@override bool searchFill() { return CatalogFactory.items.isEmpty; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return CatalogPageWidget(); }
|
||||
@override void search(BuildContext context) {
|
||||
CatalogFactory.key.currentState?.widget.search.get(context, SearchConstants.get()!).then((value) {
|
||||
if (value.data == null) { return; }
|
||||
CatalogFactory.items = [
|
||||
...value.data!.computing, ...value.data!.data, ...value.data!.storage, ...value.data!.datacenter,];
|
||||
searchWidgetKey.currentState?.setState(() {});
|
||||
@override void back(BuildContext context) {
|
||||
var s = (localStorage.getItem("search") ?? "");
|
||||
if (s != "") {
|
||||
localStorage.setItem("search", s.split(",").sublist(1).join(","));
|
||||
SearchConstants.set(s.split(",").sublist(1).join(","));
|
||||
if ((localStorage.getItem("search") ?? "") == "") {
|
||||
SearchConstants.remove();
|
||||
key.currentState?.widget.isSearch = true;
|
||||
key.currentState?.widget.items = [];
|
||||
HeaderConstants.headerKey.currentState?.setState(() {});
|
||||
HeaderConstants.headerWidget?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
} else {
|
||||
CatalogFactory().search(context, false);
|
||||
}
|
||||
} else {
|
||||
SearchConstants.remove();
|
||||
key.currentState?.widget.isSearch = true;
|
||||
key.currentState?.widget.items = [];
|
||||
HeaderConstants.headerKey.currentState?.setState(() {});
|
||||
HeaderConstants.headerWidget?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
}
|
||||
@override bool searchFill() { return (key.currentState?.widget.items.isEmpty ?? true) && (key.currentState?.widget.isSearch ?? true); }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return CatalogPageWidget(); }
|
||||
@override String? getSearch() {
|
||||
if ((localStorage.getItem("search") ?? "") == "") { return null; }
|
||||
return localStorage.getItem("search")!.split(",")[0];
|
||||
}
|
||||
@override void search(BuildContext context, bool special) {
|
||||
if (special) { return; } // T
|
||||
key.currentState?.widget.isSearch = true;
|
||||
var s = (localStorage.getItem("search") ?? "");
|
||||
if (s != "") {
|
||||
if (SearchConstants.get() == null) {
|
||||
localStorage.setItem("search", s);
|
||||
} else if (s.split(",")[0] != SearchConstants.get()) {
|
||||
localStorage.setItem("search", "${SearchConstants.get()!},$s");
|
||||
}
|
||||
} else if ((SearchConstants.get() ?? "") == "") { return;
|
||||
} else { localStorage.setItem("search", SearchConstants.get()!); }
|
||||
CatalogFactory.key.currentState?.widget.search.search(context, [
|
||||
localStorage.getItem("search")!.split(",")[0] ], {}).then((value) {
|
||||
if (value.data == null) {
|
||||
key.currentState?.widget.items = [];
|
||||
} else {
|
||||
key.currentState?.widget.isSearch = false;
|
||||
key.currentState?.widget.items = [ ...value.data!.workflows,
|
||||
...value.data!.processings, ...value.data!.datas, ...value.data!.storages, ...value.data!.computes,];
|
||||
}
|
||||
HeaderConstants.headerKey.currentState?.setState(() {});
|
||||
HeaderConstants.headerWidget?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {}); // ignore: invalid_use_of_protected_member
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class CatalogPageWidget extends StatefulWidget {
|
||||
final SearchService search = SearchService();
|
||||
CatalogPageWidget (): super(key: CatalogFactory.key);
|
||||
double? itemWidth;
|
||||
bool isSearch = true;
|
||||
List<AbstractItem> items = [];
|
||||
final ResourceService search = ResourceService();
|
||||
CatalogPageWidget ({
|
||||
this.itemWidth,
|
||||
}): super(key: CatalogFactory.key);
|
||||
@override CatalogPageWidgetState createState() => CatalogPageWidgetState();
|
||||
}
|
||||
class CatalogPageWidgetState extends State<CatalogPageWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
if (widget.items.isEmpty) {
|
||||
if (widget.isSearch) { return Container(); }
|
||||
return Container(
|
||||
width: getMainWidth(context),
|
||||
height: getMainHeight(context) - 50,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Center(child: Text("NO RESOURCES FOUND",
|
||||
style: TextStyle(fontSize: 30, color: Colors.grey))
|
||||
),
|
||||
); }
|
||||
return Column( children : [
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: CatalogFactory.items.isEmpty ? 0 : MediaQuery.of(context).size.height - HeaderConstants.height,
|
||||
child: CatalogWidget(items: CatalogFactory.items) )
|
||||
SizedBox( width: getMainWidth(context),
|
||||
height: getMainHeight(context) - 50,
|
||||
child: SingleChildScrollView( child: CatalogWidget(items: CatalogFactory.key.currentState?.widget.items, itemWidth: widget.itemWidth) )),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:localstorage/localstorage.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/pages/catalog.dart';
|
||||
import 'package:oc_front/widgets/items/item.dart';
|
||||
@@ -9,21 +13,38 @@ import 'package:oc_front/widgets/items/item_row.dart';
|
||||
|
||||
class CatalogItemFactory implements AbstractFactory {
|
||||
static GlobalKey<CatalogItemPageWidgetState> key = GlobalKey<CatalogItemPageWidgetState>();
|
||||
@override GlobalKey getKey() { return key; }
|
||||
@override void back(BuildContext context) {
|
||||
search(context, false);
|
||||
}
|
||||
@override String? getSearch() {
|
||||
if ((localStorage.getItem("search") ?? "") == "") { return null; }
|
||||
return localStorage.getItem("search")!.split(",")[0];
|
||||
}
|
||||
@override bool searchFill() { return false; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) {
|
||||
var id = state.pathParameters[args.first];
|
||||
try {
|
||||
var item = CatalogFactory.items.firstWhere( (element) => element.id == id );
|
||||
return CatalogItemPageWidget(item : item);
|
||||
var item = CatalogFactory.key.currentState?.widget.items.firstWhere( (element) => element.id == id );
|
||||
return CatalogItemPageWidget(item : item!);
|
||||
} catch (e) {
|
||||
var item = WorkspaceLocal.getItem(id ?? "");
|
||||
var item = WorkspaceLocal.getItem(id ?? "", false);
|
||||
if (item != null) { return CatalogItemPageWidget(item : item); }
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
@override void search(BuildContext context) { }
|
||||
@override void search(BuildContext context, bool special) {
|
||||
if (special) { return; } // T
|
||||
var s = SearchConstants.get();
|
||||
AppRouter.catalog.go(context, {});
|
||||
Future.delayed(Duration(milliseconds: 10), () {
|
||||
SearchConstants.set(s);
|
||||
CatalogFactory().search(context, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class CatalogItemPageWidget extends StatefulWidget {
|
||||
AbstractItem item;
|
||||
CatalogItemPageWidget ({ required this.item }) : super(key: CatalogItemFactory.key);
|
||||
@@ -32,8 +53,8 @@ class CatalogItemPageWidget extends StatefulWidget {
|
||||
class CatalogItemPageWidgetState extends State<CatalogItemPageWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
return Column( children: [
|
||||
ItemRowWidget(contextWidth: MediaQuery.of(context).size.width, item: widget.item, readOnly: true,),
|
||||
ItemWidget(item: widget.item,),
|
||||
ItemRowWidget(contextWidth: getMainWidth(context), item: widget.item, readOnly: true,),
|
||||
ItemWidget(item: widget.item),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,177 @@
|
||||
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/booking_service.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/widgets/sheduler_items/schedule.dart';
|
||||
|
||||
class DatacenterFactory implements AbstractFactory {
|
||||
static GlobalKey<DataCenterPageWidgetState> key = GlobalKey<DataCenterPageWidgetState>();
|
||||
@override GlobalKey getKey() { return key; }
|
||||
@override String? getSearch() { return ""; }
|
||||
@override void back(BuildContext context) { }
|
||||
static GlobalKey<ComputePageWidgetState> key = GlobalKey<ComputePageWidgetState>();
|
||||
@override bool searchFill() { return false; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return DataCenterPageWidget(); }
|
||||
@override void search(BuildContext context) { }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return ComputePageWidget(); }
|
||||
@override void search(BuildContext context, bool special) { }
|
||||
}
|
||||
|
||||
class DataCenterPageWidget extends StatefulWidget {
|
||||
DataCenterPageWidget () : super(key: DatacenterFactory.key);
|
||||
@override DataCenterPageWidgetState createState() => DataCenterPageWidgetState();
|
||||
// ignore: must_be_immutable
|
||||
class ComputePageWidget extends StatefulWidget {
|
||||
bool isList = true;
|
||||
DateTime start = DateTime.now();
|
||||
DateTime end = DateTime.now().add(const Duration(days: 180));
|
||||
final BookingExecutionService _service = BookingExecutionService();
|
||||
|
||||
static Widget factory() { return DataCenterPageWidget(); }
|
||||
ComputePageWidget () : super(key: DatacenterFactory.key);
|
||||
@override ComputePageWidgetState createState() => ComputePageWidgetState();
|
||||
|
||||
static Widget factory() { return ComputePageWidget(); }
|
||||
}
|
||||
class DataCenterPageWidgetState extends State<DataCenterPageWidget> {
|
||||
class ComputePageWidgetState extends State<ComputePageWidget> {
|
||||
List<Color> colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor];
|
||||
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "MISSED"];
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
return Column( children: []);
|
||||
GlobalKey<ScheduleWidgetState> k = GlobalKey<ScheduleWidgetState>();
|
||||
return Column( children: [
|
||||
Container( color: lightColor,
|
||||
height: 50, width: getMainWidth(context),
|
||||
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: getMainWidth(context) / 5,
|
||||
height: 30,
|
||||
child: DateTimeField(
|
||||
validator: (value) {
|
||||
return null;
|
||||
},
|
||||
resetIcon: null,
|
||||
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: midColor,
|
||||
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, right: 20),
|
||||
width: getMainWidth(context) / 5,
|
||||
height: 30,
|
||||
child: DateTimeField(
|
||||
validator: (value) {
|
||||
return null;
|
||||
},
|
||||
resetIcon: null,
|
||||
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: midColor,
|
||||
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),
|
||||
),
|
||||
)
|
||||
),
|
||||
Tooltip( message: "refresh scheduler",
|
||||
child: InkWell(
|
||||
onTap: () => setState(() {}),
|
||||
child: const Icon(Icons.refresh, color: Colors.white,),
|
||||
),
|
||||
)
|
||||
]))
|
||||
),
|
||||
ScheduleWidget( key: k, start: widget.start, end : widget.end, isList: widget.isList, isBox: false)
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,32 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/datacenter_service.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/widgets/items/item_row.dart';
|
||||
|
||||
|
||||
class MapFactory implements AbstractFactory {
|
||||
@override GlobalKey getKey() { return key; }
|
||||
@override String? getSearch() { return ""; }
|
||||
@override void back(BuildContext context) { }
|
||||
static GlobalKey<MapPageWidgetState> key = GlobalKey<MapPageWidgetState>();
|
||||
@override bool searchFill() { return false; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return MapPageWidget(); }
|
||||
@override void search(BuildContext context) { }
|
||||
@override void search(BuildContext context, bool special) { }
|
||||
}
|
||||
|
||||
double menuSize = 0;
|
||||
class MapPageWidget extends StatefulWidget {
|
||||
bool isShowed = false;
|
||||
final DatacenterService _service = DatacenterService();
|
||||
MapPageWidget(): super(key: MapFactory.key);
|
||||
@override MapPageWidgetState createState() => MapPageWidgetState();
|
||||
static void search(BuildContext context) { }
|
||||
@@ -21,26 +36,193 @@ class MapPageWidgetState extends State<MapPageWidget> {
|
||||
double currentZoom = 2.0;
|
||||
LatLng currentCenter = const LatLng(51.5, -0.09);
|
||||
static final MapController _mapController = MapController();
|
||||
void _zoom() {
|
||||
currentZoom = currentZoom - 1;
|
||||
_mapController.move(currentCenter, currentZoom);
|
||||
}
|
||||
bool selected = true;
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
child : FlutterMap(
|
||||
mapController: _mapController,
|
||||
options: MapOptions(
|
||||
initialCenter: currentCenter,
|
||||
initialZoom: currentZoom,
|
||||
return FutureBuilder(future: widget._service.all(context), builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||
Map<String, Map<AbstractItem, LatLng>> coordinates = {};
|
||||
List<Marker> markerCoordinates = [];
|
||||
if (snapshot.data != null&& snapshot.data!.data != null && snapshot.data!.data!.values.isNotEmpty) {
|
||||
for (var element in snapshot.data!.data!.values) {
|
||||
if (element["type"] == "storage") {
|
||||
StorageItem resource = StorageItem().deserialize(element);
|
||||
var instance = resource.getSelectedInstance();
|
||||
if (instance == null || instance.location == null) { continue; }
|
||||
if (coordinates[resource.topic] == null) { coordinates[resource.topic] = {}; }
|
||||
coordinates[resource.topic]![resource] = LatLng(instance.location!.latitude ?? 0, instance.location!.longitude ?? 0);
|
||||
} else if (element["type"] == "compute") {
|
||||
ComputeItem resource = ComputeItem().deserialize(element);
|
||||
var instance = resource.getSelectedInstance();
|
||||
if (instance == null || instance.location == null) { continue; }
|
||||
if (coordinates[resource.topic] == null) { coordinates[resource.topic] = {}; }
|
||||
var lr = Random().nextInt(max(1, 100)) / 10000;
|
||||
var lfr = Random().nextInt(max(1, 100)) / 10000;
|
||||
coordinates[resource.topic]![resource] = LatLng((instance.location!.latitude ?? 0) + lr, (instance.location!.longitude ?? 0) + lfr);
|
||||
}
|
||||
}
|
||||
for (var topic in coordinates.keys) {
|
||||
for (var coord in coordinates[topic]!.keys) {
|
||||
markerCoordinates.add(Marker(
|
||||
width: 25,
|
||||
height: 30,
|
||||
point: coordinates[topic]![coord]!,
|
||||
child: HoverMenu( width: 110, title: Container( alignment: Alignment.center,
|
||||
constraints: BoxConstraints( maxHeight: 100, maxWidth: 100 ),
|
||||
child: Icon(FontAwesomeIcons.locationDot,
|
||||
shadows: <Shadow>[Shadow(color: Color.fromRGBO(0, 0, 0, 1), blurRadius: 10.0)],
|
||||
color: getColor(topic)) ),
|
||||
items: [ Container(color: Colors.white,
|
||||
child: ItemRowWidget(low: true, contextWidth: 290, item: coord)) ]
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
Rect rect = Rect.fromCenter( center: MediaQuery.of(context).size.center(Offset.zero),
|
||||
width: selected ? menuSize : 0, height: (getMainHeight(context) - 50) > 0 ? (getMainHeight(context) - 50) : 0);
|
||||
return Expanded(
|
||||
child : FlutterMap(
|
||||
mapController: _mapController,
|
||||
options: MapOptions(
|
||||
initialCenter: currentCenter,
|
||||
initialZoom: currentZoom,
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'dev.fleaflet.flutter_map.example',
|
||||
),
|
||||
MarkerLayer(
|
||||
markers: markerCoordinates,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HoverMenuController {
|
||||
HoverMenuState? currentState;
|
||||
|
||||
void hideSubMenu() {
|
||||
currentState?.hideSubMenu();
|
||||
}
|
||||
}
|
||||
|
||||
class HoverMenu extends StatefulWidget {
|
||||
final Widget title;
|
||||
final double? width;
|
||||
final List<Widget> items;
|
||||
final HoverMenuController? controller;
|
||||
bool isHovered = false;
|
||||
|
||||
|
||||
HoverMenu({
|
||||
Key? key,
|
||||
required this.title,
|
||||
this.items = const [],
|
||||
this.width,
|
||||
this.controller,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
HoverMenuState createState() => HoverMenuState();
|
||||
}
|
||||
|
||||
class HoverMenuState extends State<HoverMenu> {
|
||||
OverlayEntry? _overlayEntry;
|
||||
final _focusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode.addListener(_onFocusChanged);
|
||||
|
||||
if (widget.controller != null) {
|
||||
widget.controller?.currentState = this;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onFocusChanged() {
|
||||
if (_focusNode.hasFocus) {
|
||||
_overlayEntry = _createOverlayEntry();
|
||||
Overlay.of(context).insert(_overlayEntry!);
|
||||
} else {
|
||||
_overlayEntry?.remove();
|
||||
_removeOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
void _removeOverlay() {
|
||||
widget.isHovered = false;
|
||||
}
|
||||
|
||||
void hideSubMenu() {
|
||||
_focusNode.unfocus();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
elevation: 0.0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0)),
|
||||
splashFactory: NoSplash.splashFactory,
|
||||
padding: EdgeInsets.zero,
|
||||
foregroundColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'dev.fleaflet.flutter_map.example',
|
||||
)
|
||||
],
|
||||
)
|
||||
focusNode: _focusNode,
|
||||
onHover: (isHovered) {
|
||||
if (isHovered && !widget.isHovered) {
|
||||
_focusNode.requestFocus();
|
||||
isHovered = true;
|
||||
} else {
|
||||
_focusNode.unfocus();
|
||||
widget.isHovered = false;
|
||||
}
|
||||
},
|
||||
onPressed: () {},
|
||||
child: widget.title,
|
||||
);
|
||||
}
|
||||
|
||||
OverlayEntry _createOverlayEntry() {
|
||||
final renderBox = context.findRenderObject() as RenderBox;
|
||||
final size = renderBox.size;
|
||||
final offset = renderBox.localToGlobal(Offset.zero);
|
||||
|
||||
return OverlayEntry(
|
||||
maintainState: true,
|
||||
builder: (context) => Positioned(
|
||||
left: offset.dx - 300,
|
||||
top: offset.dy + size.height,
|
||||
width: 300,
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0)),
|
||||
splashFactory: NoSplash.splashFactory,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {},
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
children: widget.items)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,173 @@
|
||||
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart';
|
||||
import 'package:oc_front/main.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 {
|
||||
@override GlobalKey getKey() { return key; }
|
||||
@override String? getSearch() { return ""; }
|
||||
@override void back(BuildContext context) { }
|
||||
static GlobalKey<SchedulerPageWidgetState> key = GlobalKey<SchedulerPageWidgetState>();
|
||||
@override bool searchFill() { return false; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return SchedulerPageWidget(); }
|
||||
@override void search(BuildContext context) { }
|
||||
@override void search(BuildContext context, bool special) { }
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class SchedulerPageWidget extends StatefulWidget {
|
||||
bool isList = true;
|
||||
DateTime start = DateTime.now();
|
||||
DateTime end = DateTime.now().add(const Duration(days: 180));
|
||||
final WorkflowExecutionService _service = WorkflowExecutionService();
|
||||
SchedulerPageWidget(): super(key: SchedulerFactory.key);
|
||||
@override SchedulerPageWidgetState createState() => SchedulerPageWidgetState();
|
||||
static void search(BuildContext context) { }
|
||||
static Widget factory() { return SchedulerPageWidget(); }
|
||||
}
|
||||
class SchedulerPageWidgetState extends State<SchedulerPageWidget> {
|
||||
|
||||
class SchedulerPageWidgetState extends State<SchedulerPageWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
return TableCalendar(
|
||||
firstDay: DateTime.utc(2010, 10, 16),
|
||||
lastDay: DateTime.utc(2030, 3, 14),
|
||||
focusedDay: DateTime.now(),
|
||||
);
|
||||
GlobalKey<ScheduleWidgetState> k = GlobalKey<ScheduleWidgetState>();
|
||||
return Column( children: [
|
||||
Container( color: lightColor,
|
||||
height: 50, width: getMainWidth(context),
|
||||
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: getMainWidth(context) / 5,
|
||||
height: 30,
|
||||
child: DateTimeField(
|
||||
validator: (value) {
|
||||
return null;
|
||||
},
|
||||
resetIcon: null,
|
||||
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: midColor,
|
||||
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, right: 20),
|
||||
width: getMainWidth(context) / 5,
|
||||
height: 30,
|
||||
child: DateTimeField(
|
||||
validator: (value) {
|
||||
return null;
|
||||
},
|
||||
resetIcon: null,
|
||||
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: midColor,
|
||||
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),
|
||||
),
|
||||
)
|
||||
),
|
||||
Tooltip( message: "refresh scheduler",
|
||||
child: InkWell(
|
||||
onTap: () => setState(() {}),
|
||||
child: const Icon(Icons.refresh, color: Colors.white,),
|
||||
),
|
||||
)
|
||||
]))
|
||||
),
|
||||
ScheduleWidget( key: k, start: widget.start, end : widget.end, isList: widget.isList, )
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
619
lib/pages/shared.dart
Normal file
619
lib/pages/shared.dart
Normal file
@@ -0,0 +1,619 @@
|
||||
import 'dart:async';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/models/shared.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/widgets/catalog.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/perms_service.dart';
|
||||
import 'package:oc_front/widgets/items/shallow_item_row.dart';
|
||||
import 'package:oc_front/widgets/dialog/shallow_creation.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_text_input.dart';
|
||||
import 'package:oc_front/core/models/shared_workspace_local.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/peer_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/shared_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_service.dart';
|
||||
|
||||
enum CollaborativeAreaType { global, collaborative_area, workspace, workflow, peer, resource }
|
||||
|
||||
class SharedFactory implements AbstractFactory {
|
||||
@override GlobalKey getKey() { return key; }
|
||||
@override String? getSearch() { return ""; }
|
||||
@override void back(BuildContext context) { }
|
||||
static GlobalKey<SharedPageWidgetState> key = GlobalKey<SharedPageWidgetState>();
|
||||
@override bool searchFill() { return false; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return SharedPageWidget(); }
|
||||
@override void search(BuildContext context, bool special) { }
|
||||
}
|
||||
|
||||
class SharedPageWidget extends StatefulWidget {
|
||||
CollaborativeAreaType type = CollaborativeAreaType.global;
|
||||
bool showDialog = false;
|
||||
SharedPageWidget(): super(key: SharedFactory.key);
|
||||
@override SharedPageWidgetState createState() => SharedPageWidgetState();
|
||||
static void search(BuildContext context) { }
|
||||
static Widget factory() { return SharedPageWidget(); }
|
||||
}
|
||||
class SharedPageWidgetState extends State<SharedPageWidget> {
|
||||
SharedService service = SharedService();
|
||||
Widget getMenuItem(CollaborativeAreaType workspaceType, IconData icon) {
|
||||
var s = workspaceType == CollaborativeAreaType.global ? "dashboard" : workspaceType == CollaborativeAreaType.workspace ? "shared workspaces" : workspaceType == CollaborativeAreaType.workflow ? "shared workflows" : "peers engaged";
|
||||
return Tooltip( message: s,
|
||||
child: InkWell( mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () => setState(() {
|
||||
widget.type = workspaceType;
|
||||
}),
|
||||
child: Container( width: 50, height: 50,
|
||||
color: widget.type == workspaceType ? darkColor : Colors.transparent,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child : Icon(icon,
|
||||
color: widget.type == workspaceType ? Colors.white : Colors.white, size: 20))));
|
||||
}
|
||||
@override Widget build(BuildContext context) {
|
||||
GlobalKey<ShallowTextInputWidgetState> key = GlobalKey<ShallowTextInputWidgetState>();
|
||||
if (CollaborativeAreaLocal.current == null) {
|
||||
Future.delayed( const Duration(microseconds: 100), () {
|
||||
HeaderConstants.setTitle("Choose a Collaborative Area");
|
||||
HeaderConstants.setDescription("select a shared workspace to continue");
|
||||
});
|
||||
if (!widget.showDialog) {
|
||||
Future.delayed( const Duration(milliseconds: 100), () {
|
||||
widget.showDialog = true;
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (BuildContext ctx) => AlertDialog(
|
||||
titlePadding: EdgeInsets.zero,
|
||||
insetPadding: EdgeInsets.zero,
|
||||
backgroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)),
|
||||
title: ShallowCreationDialogWidget(
|
||||
formKey: key,
|
||||
canClose: () => CollaborativeAreaLocal.current != null,
|
||||
context: context,
|
||||
load: (p0) async {
|
||||
CollaborativeAreaLocal.current = p0;
|
||||
HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>");
|
||||
HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? "");
|
||||
Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() { widget.showDialog = false; }));
|
||||
},
|
||||
form: [
|
||||
ShallowTextInputWidget(
|
||||
change :(p0) => key.currentState?.setState(() {}),
|
||||
canLoad: (po) => po != null && po.isNotEmpty,
|
||||
type: CollaborativeAreaType.collaborative_area,
|
||||
width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400,
|
||||
attr: "description",
|
||||
color: Colors.black,
|
||||
hintColor: Colors.grey,
|
||||
hint: "enter collaborative area description...",
|
||||
filled: midColor,
|
||||
)
|
||||
],
|
||||
create: PermsService.getPerm(Perms.COLLABORATIVE_AREA_CREATE) ? (p0) async => await SharedService().post(context, p0, {}).then((value) {
|
||||
if (value.data != null) {
|
||||
CollaborativeAreaLocal.current = value.data!.id;
|
||||
}
|
||||
CollaborativeAreaLocal.init(context, true);
|
||||
|
||||
HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>");
|
||||
HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? "");
|
||||
Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() { widget.showDialog = false; }));
|
||||
}) : null,
|
||||
type: CollaborativeAreaType.collaborative_area,
|
||||
all: () async {
|
||||
await CollaborativeAreaLocal.init(context, true);
|
||||
return CollaborativeAreaLocal.workspaces.values.map(
|
||||
(e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList();
|
||||
}
|
||||
)));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Future.delayed( const Duration(milliseconds: 100), () {
|
||||
HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>");
|
||||
HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? "");
|
||||
});
|
||||
}
|
||||
Widget w = WorkspaceSharedPageWidget(type: widget.type);
|
||||
List<Widget> addMenu = [];
|
||||
CollaborativeArea? current = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""];
|
||||
addMenu.add(getDropdown(widget.type, current, this, context, false));
|
||||
return Column( children: [
|
||||
Container(
|
||||
height: 50,
|
||||
color: lightColor,
|
||||
width: getMainWidth(context),
|
||||
padding: const EdgeInsets.only(left: 50),
|
||||
child: Stack( alignment: Alignment.centerLeft, children: [
|
||||
Tooltip( message: "open file", child: Padding( padding: const EdgeInsets.only(right: 15),
|
||||
child: InkWell( mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () {
|
||||
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: ShallowCreationDialogWidget(
|
||||
formKey: key,
|
||||
canClose: () => CollaborativeAreaLocal.current != null,
|
||||
context: context,
|
||||
load: (p0) async {
|
||||
CollaborativeAreaLocal.current = p0;
|
||||
HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>");
|
||||
HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? "");
|
||||
Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {}));
|
||||
},
|
||||
form: [
|
||||
ShallowTextInputWidget(
|
||||
change :(p0) => key.currentState?.setState(() {}),
|
||||
type: CollaborativeAreaType.collaborative_area,
|
||||
width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400,
|
||||
attr: "description",
|
||||
color: Colors.black,
|
||||
hintColor: Colors.grey,
|
||||
filled: midColor,
|
||||
)
|
||||
],
|
||||
create: PermsService.getPerm(Perms.COLLABORATIVE_AREA_CREATE) ? (p0) async => await SharedService().post(context, p0, {}).then( (e) async {
|
||||
if (e.data != null) {
|
||||
CollaborativeAreaLocal.current = e.data!.id;
|
||||
}
|
||||
await CollaborativeAreaLocal.init(context, true);
|
||||
setState(() {});
|
||||
}) : null,
|
||||
type: CollaborativeAreaType.collaborative_area,
|
||||
all: () async => CollaborativeAreaLocal.workspaces.values.map(
|
||||
(e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(),
|
||||
));
|
||||
});
|
||||
},
|
||||
child: const Icon(Icons.folder_open, color: Colors.white)))),
|
||||
Positioned( right: 0, child: Row( children: addMenu))
|
||||
])),
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
border: Border(left: BorderSide(color: lightColor))
|
||||
),
|
||||
height: getMainHeight(context) - 50,
|
||||
width: 50,
|
||||
child: Column(
|
||||
children: [
|
||||
getMenuItem(CollaborativeAreaType.global, Icons.dashboard),
|
||||
getMenuItem(CollaborativeAreaType.workspace, Icons.workspaces),
|
||||
getMenuItem(CollaborativeAreaType.workflow, Icons.rebase_edit),
|
||||
getMenuItem(CollaborativeAreaType.peer, Icons.group),
|
||||
])
|
||||
),
|
||||
Container(
|
||||
height: getMainHeight(context) - 50,
|
||||
width: getMainWidth(context) -50,
|
||||
color: widget.type == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer
|
||||
|| widget.type == CollaborativeAreaType.global ? midColor : Colors.white,
|
||||
child: SingleChildScrollView( child: w ))
|
||||
]
|
||||
) ]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WorkspaceSharedPageWidget extends StatefulWidget {
|
||||
CollaborativeAreaType type = CollaborativeAreaType.global;
|
||||
WorkspaceSharedPageWidget({ required this.type }): super(key: null);
|
||||
@override WorkspaceSharedPageWidgetState createState() => WorkspaceSharedPageWidgetState();
|
||||
}
|
||||
class WorkspaceSharedPageWidgetState extends State<WorkspaceSharedPageWidget> {
|
||||
|
||||
List<Widget> getCardWorkspaceItems(Map<String, List<AbstractItem>> data) {
|
||||
List<Widget> items = [];
|
||||
for (var w1 in data.keys) {
|
||||
for (var w in data[w1]!) {
|
||||
List<Widget> badges = [];
|
||||
List<Widget> bbadges = [];
|
||||
badges.add(Container( margin: const EdgeInsets.only(left: 5), padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: getColor(w.topic)
|
||||
),
|
||||
child:Text(w.topic, style: TextStyle( color: Colors.white, fontSize: 11) )));
|
||||
bbadges.add(Container( margin: const EdgeInsets.only(left: 5),
|
||||
decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(4) ),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Text(w1, style: TextStyle( color: Colors.white, fontSize: 11) )));
|
||||
items.add(ShallowItemFlowDataRowWidget(
|
||||
color: Colors.grey.shade200,
|
||||
item: w, badges: badges, bottomBadges: bbadges,
|
||||
icon: Icons.shopping_cart,
|
||||
contextWidth: 200
|
||||
));
|
||||
}}
|
||||
return items;
|
||||
}
|
||||
|
||||
List<Widget> getCardItems(List<ShallowData> data) {
|
||||
List<Widget> items = [];
|
||||
List<ShallowData> neoData = [];
|
||||
for (var d in data) {
|
||||
try { neoData.firstWhere( (e) => e.getID() == d.getID());
|
||||
} catch (e) { neoData.add(d); }
|
||||
}
|
||||
for (var w in neoData) {
|
||||
List<Widget> badges = [];
|
||||
if (w is Peer && (
|
||||
w.getID() != CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]?.rule?.creator
|
||||
|| w.getID() != CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]?.creatorID)) {
|
||||
badges.add(Padding( padding: const EdgeInsets.only(left: 5), child: Icon(Icons.star, color: Colors.orange.shade300 )));
|
||||
} else if (widget.type == CollaborativeAreaType.workspace) {
|
||||
badges.add(Container( margin: const EdgeInsets.only(left: 5), padding: EdgeInsets.all(5), color: Colors.grey.shade200,
|
||||
child: Icon(Icons.star, color: Colors.orange.shade300,)));
|
||||
}
|
||||
items.add(ShallowItemRowWidget(
|
||||
color: Colors.grey.shade200,
|
||||
item: w, badges: badges,
|
||||
delete: w is Peer ? (PermsService.getPerm(Perms.PEER_UNSHARE) && (
|
||||
w.getID() != CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]?.rule?.creator
|
||||
&& w.getID() != CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]?.creatorID) ? (String? change) async {
|
||||
await SharedService().removePeer(context, CollaborativeAreaLocal.current ?? "", change ?? "");
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
setState(() {});
|
||||
} : null) : (w is Workflow && PermsService.getPerm(Perms.WORKSPACE_UNSHARE)) ? (String? change) async {
|
||||
await SharedService().removeWorkflow(context, CollaborativeAreaLocal.current ?? "", change ?? "");
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
setState(() {});
|
||||
} : null,
|
||||
icon: w is Workflow ? Icons.work_history_rounded : Icons.person,
|
||||
contextWidth: 200
|
||||
));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
var space = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""];
|
||||
if (widget.type == CollaborativeAreaType.global) {
|
||||
if (space == null) {
|
||||
return Container(
|
||||
color: midColor,
|
||||
height: getMainHeight(context) - 50,
|
||||
width: getMainWidth(context) - 50,
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.all(50)
|
||||
);
|
||||
}
|
||||
final DateFormat formatter = DateFormat('dd-MM-yyyy');
|
||||
Peer? creator;
|
||||
SharedService service = SharedService();
|
||||
try { creator = space.peers.firstWhere( (e) => (space.rule?.creator ?? "") == e.id);
|
||||
} catch (e) { /**/ }
|
||||
Map<String, List<AbstractItem>> datas = {};
|
||||
for (var w in space.workspaces) {
|
||||
datas[w.getName()] =<AbstractItem> [
|
||||
...w.computes,
|
||||
...w.datas,
|
||||
...w.processings,
|
||||
...w.storages,
|
||||
...w.workflows
|
||||
];
|
||||
}
|
||||
return Padding( padding: EdgeInsets.all(30),
|
||||
child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Row( mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Text((CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? "").toUpperCase(),
|
||||
style: TextStyle(color: Colors.grey, fontSize: 25, fontWeight: FontWeight.bold), textAlign: TextAlign.center,
|
||||
softWrap: true, overflow: TextOverflow.ellipsis,),
|
||||
]),
|
||||
Container(
|
||||
width: getMainWidth(context) - 50,
|
||||
margin: EdgeInsets.symmetric(vertical: 20),
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50),
|
||||
child: Text(space.description ?? "",
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400, color: Colors.grey))
|
||||
),
|
||||
Padding( padding: EdgeInsets.only(left: 30), child: Text("COLLABORATIVE AREA ACCESS RULES", textAlign: TextAlign.start,
|
||||
style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip)),
|
||||
Container(
|
||||
width: getMainWidth(context) - 50,
|
||||
margin: EdgeInsets.symmetric(vertical: 20),
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(children: [ Text("Share mode : "), Text( space.rule?.shareMode ?? "closed", style: TextStyle( fontWeight: FontWeight.bold ) )],),
|
||||
Row(children: [ Text("Created : "), Text( formatter.format(space.rule?.createdAt ?? DateTime.now()), style: TextStyle( fontWeight: FontWeight.bold )) ],),
|
||||
creator != null ? Row(children: [ Text("Area master : "), Text( creator.getName(), style: TextStyle( fontWeight: FontWeight.bold ) ) ],)
|
||||
: Container(),
|
||||
Row(children: [ Text("User count : "), Text( "${space.peers.length}", style: TextStyle( fontWeight: FontWeight.bold )) ],),
|
||||
Row(children: [ Text("Users profile : "), Text( space.rule?.exploitedBy ?? "any", style: TextStyle( fontWeight: FontWeight.bold ) ) ],),
|
||||
],
|
||||
)
|
||||
),
|
||||
|
||||
Row( children: [
|
||||
Padding( padding: EdgeInsets.only(left: 30), child: Text("COLLABORATIVE AREA PEERS", textAlign: TextAlign.start,
|
||||
style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip)),
|
||||
PermsService.getPerm(Perms.PEER_SHARE) ? Container(
|
||||
margin: EdgeInsets.only(left: 20), padding: EdgeInsets.only(left: 15),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(left: BorderSide(color: Colors.grey))
|
||||
), child: getDropdown(CollaborativeAreaType.peer, CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current], this, context, true)
|
||||
) : Container()]),
|
||||
Container(
|
||||
width: getMainWidth(context) - 50,
|
||||
margin: EdgeInsets.symmetric(vertical: 20),
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50),
|
||||
child: Wrap( alignment: WrapAlignment.center, children: getCardItems(space.peers)),
|
||||
),
|
||||
space.rules.isNotEmpty ? Padding( padding: EdgeInsets.only(left: 30), child: Text("RULES", textAlign: TextAlign.start,
|
||||
style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip)) : Container(),
|
||||
space.rules.isNotEmpty ? Container(
|
||||
width: getMainWidth(context) - 50,
|
||||
margin: EdgeInsets.symmetric(vertical: 20),
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50),
|
||||
child: Column( children: space.rules.map( (e) {
|
||||
return Row( children: [
|
||||
Padding( padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
child:Text("-", style: TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.bold), overflow: TextOverflow.clip)),
|
||||
Text(e ?? "", style: TextStyle(color: Colors.grey, fontSize: 15), overflow: TextOverflow.clip)
|
||||
]);
|
||||
}).toList() )
|
||||
) : Container(),
|
||||
Row( children: [
|
||||
Padding( padding: EdgeInsets.only(left: 30), child: Text("WORKSPACES / RESOURCES", textAlign: TextAlign.start,
|
||||
style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip)),
|
||||
PermsService.getPerm(Perms.WORKSPACE_SHARE) ? Container(
|
||||
margin: EdgeInsets.only(left: 20), padding: EdgeInsets.only(left: 15),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(left: BorderSide(color: Colors.grey))
|
||||
), child: getDropdown(CollaborativeAreaType.workspace, CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current], this, context, true)) : Container() ]),
|
||||
Container(
|
||||
width: getMainWidth(context) - 50,
|
||||
margin: EdgeInsets.symmetric(vertical: 20),
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50),
|
||||
child: Wrap( alignment: WrapAlignment.center, children: getCardWorkspaceItems(datas))
|
||||
),
|
||||
Row( children: [
|
||||
Padding( padding: EdgeInsets.only(left: 30), child: Text("WORKFLOWS", textAlign: TextAlign.start,
|
||||
style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip)),
|
||||
PermsService.getPerm(Perms.WORKFLOW_SHARE) ? Container(
|
||||
margin: EdgeInsets.only(left: 20), padding: EdgeInsets.only(left: 15),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(left: BorderSide(color: Colors.grey))
|
||||
), child: getDropdown(CollaborativeAreaType.workflow, CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current], this, context, true)) : Container()]),
|
||||
Container(
|
||||
width: getMainWidth(context) - 50,
|
||||
margin: EdgeInsets.symmetric(vertical: 20),
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50),
|
||||
child: Wrap( alignment: WrapAlignment.center, children: getCardItems(space.workflows))
|
||||
),
|
||||
],)
|
||||
);
|
||||
}
|
||||
|
||||
if (CollaborativeAreaLocal.current == null) {
|
||||
return Container(
|
||||
color: midColor,
|
||||
height: getMainHeight(context) - 50,
|
||||
width: getMainWidth(context) - 50,
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.all(50)
|
||||
);
|
||||
}
|
||||
List<Widget> items = [];
|
||||
List<ShallowData> data = [];
|
||||
if (widget.type == CollaborativeAreaType.workspace) {
|
||||
data = space?.workspaces ?? [];
|
||||
} else if (widget.type == CollaborativeAreaType.workflow) {
|
||||
data = space?.workflows ?? [];
|
||||
} else if (widget.type == CollaborativeAreaType.peer) {
|
||||
data = space?.peers ?? [];
|
||||
}
|
||||
if (widget.type == CollaborativeAreaType.workspace) {
|
||||
List<ShallowData> neoData = [];
|
||||
for (var d in data) {
|
||||
try { neoData.firstWhere( (e) => e.getID() == d.getID());
|
||||
} catch (e) { neoData.add(d); }
|
||||
}
|
||||
for (var w in neoData) {
|
||||
if (WorkspaceLocal.workspaces[w.getID()] == null) { continue; }
|
||||
items.add(WorkspaceSharedItemPageWidget(name: "Workspace <${WorkspaceLocal.workspaces[w.getID()]!.name}>", id: w.getID()));
|
||||
}
|
||||
} else {
|
||||
items = getCardItems(data);
|
||||
}
|
||||
if (items.isEmpty) {
|
||||
return Container(
|
||||
color: midColor,
|
||||
height: getMainHeight(context) - 50,
|
||||
width: getMainWidth(context) - 50,
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.all(50),
|
||||
child: Text("NO ITEMS SHARED", style: const TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white)));
|
||||
}
|
||||
if (widget.type == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(50),
|
||||
child: Stack( alignment: Alignment.topLeft, children : items));
|
||||
}
|
||||
return Column( mainAxisAlignment: MainAxisAlignment.start, children : items);
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class WorkspaceSharedItemPageWidget extends StatefulWidget {
|
||||
bool open = true;
|
||||
String id = "";
|
||||
String name = "";
|
||||
WorkspaceSharedItemPageWidget({ this.name = "", this.id = "" }): super(key: null);
|
||||
@override WorkspaceSharedItemPageWidgetState createState() => WorkspaceSharedItemPageWidgetState();
|
||||
}
|
||||
class WorkspaceSharedItemPageWidgetState extends State<WorkspaceSharedItemPageWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
return Column( children: [
|
||||
Container(
|
||||
width: getMainWidth(context) - 50,
|
||||
height: 50,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
decoration: BoxDecoration(color: midColor, border: Border(bottom: BorderSide(color: Colors.white))),
|
||||
child: Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Padding(padding: EdgeInsets.only(right: 20), child: Icon(Icons.shopping_cart_outlined, size: 18, color: Colors.grey)),
|
||||
Text(widget.name,
|
||||
style: const TextStyle(fontSize: 15, color: Colors.grey, fontWeight: FontWeight.w600)),
|
||||
]
|
||||
),
|
||||
Positioned( right: 0, top: 5, child: IconButton( icon: Icon(widget.open ? Icons.arrow_drop_up : Icons.arrow_drop_down, color: Colors.grey),
|
||||
onPressed: () => setState(() {
|
||||
widget.open = !widget.open;
|
||||
})))
|
||||
])
|
||||
),
|
||||
widget.open ? CatalogWidget(itemWidth: getMainWidth(context) - 50,
|
||||
items: WorkspaceLocal.byWorkspace(widget.id)) : Container()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Widget getDropdown(CollaborativeAreaType type, CollaborativeArea? current, State<dynamic> state, BuildContext context, bool mainPage ) {
|
||||
if (type == CollaborativeAreaType.workspace) {
|
||||
return Row( mainAxisAlignment: MainAxisAlignment.end,
|
||||
children : [ Container( padding: EdgeInsets.only(left: mainPage ? 0 : 20), decoration: BoxDecoration(
|
||||
border: mainPage ? null : Border(left: BorderSide(color: Colors.white))
|
||||
), child: ShallowDropdownInputWidget(
|
||||
tooltipLoad: "share",
|
||||
tooltipRemove: "unshare",
|
||||
iconLoad: Icons.share,
|
||||
type: type,
|
||||
filled: mainPage ? Colors.white : lightColor,
|
||||
hintColor: mainPage ? Colors.grey : midColor,
|
||||
color: mainPage ? Colors.black : Colors.white,
|
||||
prefixIcon: Icon(Icons.shopping_cart, color: Colors.white),
|
||||
current: WorkspaceLocal.current,
|
||||
all: () async => WorkspaceLocal.getWorkspacesShallow(),
|
||||
width: getMainWidth(context) / 3,
|
||||
canLoad: (String? change) => current != null && !current.workspaces.map( (e) => e.id ).contains(change),
|
||||
canRemove: (String? change) => current != null && current.workspaces.map( (e) => e.id ).contains(change),
|
||||
load: PermsService.getPerm(Perms.WORKSPACE_SHARE) ? (String val) async {
|
||||
await SharedService().addWorkspace(context, CollaborativeAreaLocal.current ?? "", val);
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
state.setState(() {});
|
||||
if (mainPage) {
|
||||
SharedFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
} : null,
|
||||
remove: PermsService.getPerm(Perms.WORKSPACE_UNSHARE) ? (String val) async {
|
||||
await SharedService().removeWorkspace(context, CollaborativeAreaLocal.current ?? "", val);
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
state.setState(() {});
|
||||
if (mainPage) {
|
||||
SharedFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
} : null))
|
||||
]);
|
||||
}
|
||||
if (type == CollaborativeAreaType.workflow) {
|
||||
return Row( mainAxisAlignment: MainAxisAlignment.end,
|
||||
children : [ Container( padding: EdgeInsets.only(left: mainPage ? 0 : 20), decoration: BoxDecoration(
|
||||
border: mainPage ? null : Border(left: BorderSide(color: Colors.white))
|
||||
), child: ShallowDropdownInputWidget(
|
||||
tooltipLoad: "share",
|
||||
tooltipRemove: "unshare",
|
||||
iconLoad: Icons.share,
|
||||
filled: mainPage ? Colors.white : lightColor,
|
||||
hintColor: mainPage ? Colors.grey : midColor,
|
||||
color: mainPage ? Colors.black : Colors.white,
|
||||
type: type, all: () async {
|
||||
List<Shallow> shals = [];
|
||||
await WorflowService().all(context).then((value) {
|
||||
if (value.data != null) {
|
||||
shals = value.data!.values.map((e) => Shallow(id: e["id"], name: e["name"])).toList();
|
||||
}
|
||||
});
|
||||
return shals;
|
||||
},
|
||||
width: getMainWidth(context) / 3,
|
||||
canLoad: (String? change) => current != null && !current.workflows.map( (e) => e.id ).contains(change),
|
||||
canRemove: (String? change) => current != null && current.workflows.map( (e) => e.id ).contains(change),
|
||||
load: PermsService.getPerm(Perms.WORKFLOW_SHARE) ? (String change) async {
|
||||
await SharedService().addWorkflow(context, CollaborativeAreaLocal.current ?? "", change);
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
state.setState(() {});
|
||||
if (mainPage) {
|
||||
SharedFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
} : null,
|
||||
remove: PermsService.getPerm(Perms.WORKFLOW_UNSHARE) ? (String change) async {
|
||||
await SharedService().removeWorkflow(context, CollaborativeAreaLocal.current ?? "", change);
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
state.setState(() {});
|
||||
if (mainPage) {
|
||||
SharedFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
} : null))
|
||||
]);
|
||||
}
|
||||
if (type == CollaborativeAreaType.peer) {
|
||||
return Row( mainAxisAlignment: MainAxisAlignment.end,
|
||||
children : [
|
||||
Container( padding: EdgeInsets.only(left: mainPage ? 0 : 20), decoration: BoxDecoration(
|
||||
border: mainPage ? null : Border(left: BorderSide(color : Colors.white))
|
||||
), child: ShallowDropdownInputWidget(
|
||||
tooltipLoad: "add",
|
||||
iconLoad: Icons.add,
|
||||
filled: mainPage ? Colors.white : lightColor,
|
||||
hintColor: mainPage ? Colors.grey : midColor,
|
||||
color: mainPage ? Colors.black : Colors.white,
|
||||
type: type, all: () async {
|
||||
List<Shallow> shals = [];
|
||||
await PeerService().all(context).then((value) {
|
||||
if (value.data != null) {
|
||||
shals = value.data!.values.where( (e) {
|
||||
return e["id"] != current?.creatorID;
|
||||
}
|
||||
).map((e) => Shallow(id: e["id"], name: e["name"])).toList();
|
||||
}
|
||||
});
|
||||
return shals;
|
||||
},
|
||||
width: getMainWidth(context) / 3,
|
||||
canLoad: (String? change) => current != null && !current.peers.map( (e) => e.id ).contains(change),
|
||||
canRemove: (String? change) => current != null && current.peers.map( (e) => e.id ).contains(change),
|
||||
load: PermsService.getPerm(Perms.PEER_SHARE) ? (String change) async {
|
||||
await SharedService().addPeer(context, CollaborativeAreaLocal.current ?? "", change);
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
state.setState(() {});
|
||||
if (mainPage) {
|
||||
SharedFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
} : null,
|
||||
remove: PermsService.getPerm(Perms.PEER_UNSHARE) ? (String change) async {
|
||||
await SharedService().removePeer(context, CollaborativeAreaLocal.current ?? "", change);
|
||||
await CollaborativeAreaLocal.init(context, false);
|
||||
state.setState(() {});
|
||||
if (mainPage) {
|
||||
SharedFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
} : null))
|
||||
]);
|
||||
}
|
||||
return Container();
|
||||
}
|
||||
@@ -1,26 +1,49 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/perms_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_service.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/data.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/resources/storage.dart';
|
||||
import 'package:oc_front/models/resources/workflow.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/widgets/dialog/new_box.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/widgets/dialog/shallow_creation.dart';
|
||||
import 'package:oc_front/widgets/forms/resource_forms.dart';
|
||||
import 'package:oc_front/widgets/forms/scheduler_forms.dart';
|
||||
import 'package:oc_front/widgets/forms/storage_processing_link_forms.dart';
|
||||
import 'package:oc_front/widgets/items/item_row.dart';
|
||||
Dashboard dash = Dashboard(name: "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}");
|
||||
import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart';
|
||||
|
||||
Dashboard dash = Dashboard(name: "");
|
||||
class WorkflowFactory implements AbstractFactory {
|
||||
@override GlobalKey getKey() { return key; }
|
||||
@override String? getSearch() { return ""; }
|
||||
@override void back(BuildContext context) { }
|
||||
static GlobalKey<WorkflowPageWidgetState> key = GlobalKey<WorkflowPageWidgetState>();
|
||||
@override bool searchFill() { return false; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return WorkflowPageWidget(); }
|
||||
@override void search(BuildContext context) { }
|
||||
@override Widget factory(GoRouterState state, List<String> args) {
|
||||
String? id;
|
||||
try { id = state.pathParameters[args.first];
|
||||
} catch (e) { /**/ }
|
||||
return WorkflowPageWidget(id: id);
|
||||
}
|
||||
@override void search(BuildContext context, bool special) { }
|
||||
}
|
||||
bool getAll = true;
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class WorkflowPageWidget extends StatefulWidget {
|
||||
WorkflowPageWidget () : super(key: WorkflowFactory.key);
|
||||
String? id;
|
||||
WorkflowPageWidget ({ this.id }) : super(key: WorkflowFactory.key);
|
||||
@override WorkflowPageWidgetState createState() => WorkflowPageWidgetState();
|
||||
static void search(BuildContext context) { }
|
||||
static Widget factory() { return WorkflowPageWidget(); }
|
||||
@@ -29,42 +52,298 @@ class WorkflowPageWidgetState extends State<WorkflowPageWidget> {
|
||||
final WorflowService _service = WorflowService();
|
||||
Widget itemBuild(Object item) {
|
||||
var e = item as AbstractItem;
|
||||
return e.logo != null ? Image.memory(base64Decode(e.logo ?? ""), fit: BoxFit.fill)
|
||||
: Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', fit: BoxFit.fill);
|
||||
return Tooltip( message: item.name ?? "",
|
||||
child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill)
|
||||
: Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp',
|
||||
fit: BoxFit.fill));
|
||||
}
|
||||
Widget itemTooltipBuild(Object item) {
|
||||
var e = item as AbstractItem;
|
||||
return Container(color: Colors.white, child: ItemRowWidget(low: true, contextWidth: 300, item: e));
|
||||
return Container(color: Colors.white, child: ItemRowWidget(low: true, contextWidth: 290, item: e));
|
||||
}
|
||||
List<DropdownMenuItem> getItems(Object? data) {
|
||||
data = data as APIResponse<RawData>?;
|
||||
if (data != null && data.data != null && data.data!.values.isNotEmpty) {
|
||||
return (data.data!.values as List<dynamic>).map((dynamic value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value.toString(),
|
||||
child: Text(value.toString()),
|
||||
);
|
||||
}).toList();
|
||||
Widget getArrowForms(ArrowPainter? arrow) {
|
||||
if (arrow == null) { return Container(); }
|
||||
var from = dash.getElement(arrow.fromID);
|
||||
var to = dash.getElement(arrow.toID);
|
||||
if ((from?.element?.getType() == "storage" && to?.element?.getType() == "processing")
|
||||
|| (from?.element?.getType() == "processing" && to?.element?.getType() == "storage")) {
|
||||
return StorageProcessingLinkFormsWidget( dash: dash, item: arrow);
|
||||
}
|
||||
return [];
|
||||
return Container();
|
||||
}
|
||||
List<Widget> getForms(FlowData? obj, String id) {
|
||||
var objAbs = obj as AbstractItem?;
|
||||
if (objAbs == null) { return []; }
|
||||
List<Widget> res = [ ResourceFormsWidget(item: objAbs, dash: dash, elementID: id) ];
|
||||
return [ Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
Container( padding: const EdgeInsets.all(10), width: 250, height: 60,
|
||||
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),
|
||||
])),
|
||||
...res
|
||||
]) ];
|
||||
}
|
||||
|
||||
Widget? getTopRight(FlowData? obj) {
|
||||
var objAbs = obj as AbstractItem?;
|
||||
if (objAbs == null) { return null; }
|
||||
if (objAbs.topic == "compute") {
|
||||
var instance = objAbs as ComputeItem;
|
||||
if (instance.infrastructureEnum != null) {
|
||||
if (instance.infrastructureEnum == 0) {
|
||||
return Icon(FontAwesomeIcons.docker, size: 16);
|
||||
} else if (instance.infrastructureEnum == 1) {
|
||||
return Icon(FontAwesomeIcons.lifeRing, size: 16);
|
||||
} else if (instance.infrastructureEnum == 2) {
|
||||
return Icon(FontAwesomeIcons.cubes, size: 16);
|
||||
} else if (instance.infrastructureEnum == 3) {
|
||||
return Icon(FontAwesomeIcons.hardDrive, size: 16);
|
||||
} else if (instance.infrastructureEnum == 4) {
|
||||
return Icon(FontAwesomeIcons.v, size: 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget? getBottomLeftBadge(FlowData? obj) {
|
||||
var objAbs = obj as AbstractItem?;
|
||||
if (objAbs == null) { return null; }
|
||||
if (objAbs.topic == "processing" ) {
|
||||
return Icon(FontAwesomeIcons.gear, size: 16);
|
||||
} else if (objAbs.topic == "data" ) {
|
||||
return Icon(FontAwesomeIcons.file, size: 16);
|
||||
} else if (objAbs.topic == "storage" ) {
|
||||
return Icon(FontAwesomeIcons.database, size: 16);
|
||||
} else if (objAbs.topic == "compute" ) {
|
||||
return Icon(FontAwesomeIcons.microchip, size: 16);
|
||||
} else if (objAbs.topic == "workflows" ) {
|
||||
return Icon(FontAwesomeIcons.diagramProject, size: 16);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Widget> getDashInfoForms() {
|
||||
return [
|
||||
SchedulerFormsWidget(item: dash),
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> loadDash(String selected) async {
|
||||
dash.shouldSave = false;
|
||||
dash.name = "";
|
||||
var name = "";
|
||||
if (selected.split("~").length > 1) {
|
||||
name = selected.split("~")[1];
|
||||
dash.id = selected.split("~")[0];
|
||||
} else {
|
||||
name = selected;
|
||||
}
|
||||
await _service.get(context, dash.id ?? "").then((value) async {
|
||||
if (value.data != null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
await WorkspaceLocal.init(context, false);
|
||||
WorkspaceLocal.changeWorkspaceByName("${value.data?.name ?? ""}_workspace");
|
||||
dash.clear();
|
||||
dash.deserialize(value.data!.toDashboard(), false);
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
dash.name = name;
|
||||
dash.shouldSave = true;
|
||||
dash.selectedMenuKey.currentState?.setState(() { });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> saveDash(String? id, BuildContext? context) async {
|
||||
if (id == null || !dash.isOpened || !dash.shouldSave || !PermsService.getPerm(Perms.WORKFLOW_EDIT)) { return; }
|
||||
var datas = dash.elements.where( (e) => e.element?.serialize()["type"] == "data");
|
||||
var compute = dash.elements.where( (e) => e.element?.serialize()["type"] == "compute");
|
||||
var storage = dash.elements.where( (e) => e.element?.serialize()["type"] == "storage");
|
||||
var processing = dash.elements.where( (e) => e.element?.serialize()["type"] == "processing");
|
||||
var workflows = dash.elements.where( (e) => e.element?.serialize()["type"] == "workflow");
|
||||
var updateW = Workflow(
|
||||
name: dash.name,
|
||||
graph: Graph(),
|
||||
data: datas.map((e) => e.id).toSet().toList(),
|
||||
compute: compute.map((e) => e.id).toSet().toList(),
|
||||
storage: storage.map((e) => e.id).toSet().toList(),
|
||||
processing: processing.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) + (item.width! / 2) + 7.5;
|
||||
item.position?.y = (item.position?.y ?? 0) + (item.height! / 2) + 7.5;
|
||||
for (var i in (updateW.graph?.links ?? [] as List<GraphLink>).where((element) => id == element.source?.id)) {
|
||||
i.source?.x = (i.source?.x ?? 0) + (item.width! / 2) + 7.5;
|
||||
i.source?.y = (i.source?.y ?? 0) + (item.width! / 2) + 7.5;
|
||||
}
|
||||
for (var i in (updateW.graph?.links ?? [] as List<GraphLink>).where((element) => id == element.destination?.id)) {
|
||||
i.destination?.x = (i.destination?.x ?? 0) + (item.width! / 2) + 7.5;
|
||||
i.destination?.y = (i.destination?.y ?? 0) + (item.width! / 2) + 7.5;
|
||||
}
|
||||
}
|
||||
updateW.graph?.zoom = dash.getZoomFactor();
|
||||
dash.addToHistory();
|
||||
_service.put(null, id, updateW.serialize(), {}).then( (e) async {
|
||||
dash.applyInfos(updateW.graph?.getEnvToUpdate() ?? {}, updateW.toDashboard());
|
||||
if (dash.addChange) {
|
||||
dash.addChange = false;
|
||||
// ignore: use_build_context_synchronously
|
||||
await WorkspaceLocal.init(context, false);
|
||||
WorkspaceLocal.changeWorkspaceByName("${dash.name}_workspace");
|
||||
dash.selectedLeftMenuKey.currentState?.setState(() { });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
FlowData? transformToData(Map<String, dynamic> data) {
|
||||
if (data["type"] == "data") { return DataItem().deserialize(data); }
|
||||
if (data["type"] == "compute") { return ComputeItem().deserialize(data); }
|
||||
if (data["type"] == "storage") { return StorageItem().deserialize(data); }
|
||||
if (data["type"] == "processing") { return ProcessingItem().deserialize(data); }
|
||||
if (data["type"] == "workflows") { return WorkflowItem().deserialize(data); }
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget onDashboardMenu(Dashboard dash) {
|
||||
return Container( padding: EdgeInsets.only(left: 50),
|
||||
decoration: BoxDecoration( border: Border( left: BorderSide( color: Colors.white ))),
|
||||
child: ShallowDropdownInputWidget(
|
||||
filled: lightColor,
|
||||
hintColor: Colors.grey.shade200,
|
||||
color: Colors.white,
|
||||
prefixIcon: Padding( padding: EdgeInsets.only(right: 10), child: Icon(Icons.shopping_cart, color: Colors.grey.shade200)),
|
||||
current: WorkspaceLocal.current,
|
||||
width: 300,
|
||||
all: () async => WorkspaceLocal.getWorkspacesShallow(),
|
||||
type: CollaborativeAreaType.workspace,
|
||||
change: (String? change) {
|
||||
WorkspaceLocal.changeWorkspace(change.toString());
|
||||
},
|
||||
canLoad: (p0) => true,
|
||||
load: (p0) async {
|
||||
dash.isInfo = !dash.isInfo;
|
||||
dash.flutterChartKey.currentState?.setState(() { });
|
||||
},
|
||||
tooltipLoad: "open workspace manager",
|
||||
iconLoad: dash.isInfo ? Icons.remove_red_eye_outlined : Icons.remove_red_eye,
|
||||
));
|
||||
}
|
||||
Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) {
|
||||
return NewBoxWidget<RawData>(service: _service, dash: dash,
|
||||
getItems: getItems);
|
||||
return ShallowCreationDialogWidget(
|
||||
canClose: () => dash.isOpened,
|
||||
context: context,
|
||||
load: (p0) async {
|
||||
dash.isOpened = true;
|
||||
if (dash.load != null) {
|
||||
WorkspaceLocal.changeWorkspaceByName(p0.split("~")[1]);
|
||||
await dash.load!(p0);
|
||||
}
|
||||
dash.inDialog = false;
|
||||
dash.notifyListeners();
|
||||
},
|
||||
create: PermsService.getPerm(Perms.WORKFLOW_CREATE) ? (p0) async => await _service.post(context, p0, {}).then( (value) async {
|
||||
dash.clear();
|
||||
dash.id = value.data?.getID() ?? "";
|
||||
dash.name = value.data?.getName() ?? "";
|
||||
dash.inDialog = false;
|
||||
dash.notifyListeners();
|
||||
await WorkspaceLocal.init(context, true);
|
||||
dash.isOpened = true;
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
dash.load!("${dash.id}~${dash.name}");
|
||||
});
|
||||
}
|
||||
) : null,
|
||||
maptoDropdown: (e) => DropdownMenuItem<String>(
|
||||
value: "${e.id}~${e.name}",
|
||||
child: Text(e.name),
|
||||
),
|
||||
type: CollaborativeAreaType.workflow,
|
||||
all: () async {
|
||||
List<Shallow> res = [];
|
||||
await _service.all(context).then(
|
||||
(e) {
|
||||
if (e.data != null) {
|
||||
res = e.data!.values.map((e) => Shallow(id: e["id"] ?? "", name: e["name"] ?? "")).toList();
|
||||
}
|
||||
}
|
||||
);
|
||||
return res;
|
||||
}
|
||||
);
|
||||
}
|
||||
@override Widget build(BuildContext context) {
|
||||
var quart = MediaQuery.of(context).size.width / 6;
|
||||
dash.defaultName = "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}";
|
||||
dash.load = loadDash;
|
||||
dash.save = saveDash;
|
||||
dash.dashColor = lightColor;
|
||||
dash.midDashColor = midColor;
|
||||
dash.transformToData = transformToData;
|
||||
dash.infoItemWidget = getForms;
|
||||
dash.infoLinkWidget = getArrowForms;
|
||||
dash.infoWidget = getDashInfoForms;
|
||||
dash.widthOffset = 50;
|
||||
dash.arrowStyleRules = [
|
||||
(dash) {
|
||||
for (var arrow in dash.arrows) {
|
||||
try {
|
||||
var from = dash.elements.firstWhere((element) => arrow.fromID.split("_")[0] == element.id).element;
|
||||
var to = dash.elements.firstWhere((element) => arrow.toID.split("_")[0] == element.id).element;
|
||||
if ((from is ProcessingItem && to is ComputeItem) || (to is ProcessingItem && from is ComputeItem)) {
|
||||
arrow.params.color = Colors.orange;
|
||||
arrow.params.dashSpace = 2;
|
||||
arrow.params.dashWidth = 2;
|
||||
} else if ((from is ProcessingItem && to is StorageItem) || (to is ProcessingItem && from is StorageItem)) {
|
||||
arrow.params.color = redColor;
|
||||
arrow.params.dashSpace = 2;
|
||||
arrow.params.dashWidth = 2;
|
||||
} else if ((from is ProcessingItem && to is DataItem) || (to is ProcessingItem && from is DataItem)) {
|
||||
arrow.params.color = Colors.blue;
|
||||
arrow.params.dashSpace = 2;
|
||||
arrow.params.dashWidth = 2;
|
||||
} else {
|
||||
arrow.params.color = Colors.black;
|
||||
arrow.params.dashSpace = 0;
|
||||
arrow.params.dashWidth = 0;
|
||||
}
|
||||
} catch (e) {
|
||||
arrow.params.color = Colors.black;
|
||||
arrow.params.dashSpace = 0;
|
||||
arrow.params.dashWidth = 0;
|
||||
}
|
||||
}
|
||||
return dash.arrows;
|
||||
}
|
||||
];
|
||||
dash.saveRules = [
|
||||
(dash) {
|
||||
dash.error = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
];
|
||||
return FlowChart<AbstractItem>(
|
||||
key: dash.flutterChartKey,
|
||||
itemLeftBottomBadges: getBottomLeftBadge,
|
||||
itemrightTopBadges: getTopRight,
|
||||
onDashboardAlertOpened: onDashboardAlertOpened,
|
||||
dashboard: dash,
|
||||
current: widget.id,
|
||||
itemWidget: itemBuild,
|
||||
categories: const ["computing", "data", "datacenter", "storage"],
|
||||
draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat).toList(),
|
||||
menuWidget: onDashboardMenu,
|
||||
categories: const ["processing", "data", "compute", "storage", "workflows"],
|
||||
draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, false),
|
||||
itemWidgetTooltip: itemTooltipBuild,
|
||||
innerMenuWidth: quart > 80 ? quart : 80,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height - HeaderConstants.height,
|
||||
innerMenuWidth: 350,
|
||||
width: getMainWidth(context),
|
||||
height: getMainHeight(context),
|
||||
onNewConnection: (p1, p2) { },
|
||||
onDashboardTapped: (context, position) { },
|
||||
onScaleUpdate: (newScale) { },
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/widgets/items/item_row.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
|
||||
class CatalogWidget extends StatefulWidget {
|
||||
double? itemWidth;
|
||||
bool readOnly = false;
|
||||
final List<AbstractItem>? items;
|
||||
CatalogWidget ({ Key? key, this.items }): super(key: key);
|
||||
CatalogWidget ({ super.key, this.items, this.itemWidth, this.readOnly = false });
|
||||
@override CatalogWidgetState createState() => CatalogWidgetState();
|
||||
}
|
||||
class CatalogWidgetState extends State<CatalogWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
var items = widget.items ?? WorkspaceLocal.items;
|
||||
List<ItemRowWidget> itemRows = items.map((e) => ItemRowWidget(contextWidth: MediaQuery.of(context).size.width, item: e)).toList();
|
||||
return SingleChildScrollView( child: Column( children: itemRows) );
|
||||
List<ItemRowWidget> itemRows = items.map((e) => ItemRowWidget(
|
||||
readOnly: widget.readOnly,
|
||||
contextWidth: widget.itemWidth ?? getMainWidth(context), item: e)).toList();
|
||||
return Column( children: itemRows);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
|
||||
class InfoAlertBannerChild extends StatelessWidget {
|
||||
final String text;
|
||||
@@ -9,7 +10,7 @@ class InfoAlertBannerChild extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.8),
|
||||
constraints: BoxConstraints(maxWidth: getMainWidth(context) * 0.8),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.greenAccent,
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
@@ -38,9 +39,9 @@ class AlertAlertBannerChild extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.8),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.redAccent,
|
||||
constraints: BoxConstraints(maxWidth: getMainWidth(context) * 0.8),
|
||||
decoration: BoxDecoration(
|
||||
color: redColor,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5),
|
||||
),
|
||||
|
||||
@@ -1,71 +1,140 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/core/services/auth.service.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/pages/workflow.dart';
|
||||
|
||||
class LoginWidget extends StatefulWidget {
|
||||
LoginWidget ({ Key? key }): super(key: key);
|
||||
@override LoginWidgetState createState() => LoginWidgetState();
|
||||
}
|
||||
class LoginWidgetState extends State<LoginWidget> {
|
||||
TextEditingController usernameCtrl = TextEditingController();
|
||||
TextEditingController passwordCtrl = TextEditingController();
|
||||
|
||||
String? error;
|
||||
bool loading = false;
|
||||
FocusNode focusNode = FocusNode();
|
||||
@override Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(0))),
|
||||
content: Padding(padding: const EdgeInsets.all(20), child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
const Center(child: Padding( padding: EdgeInsets.only(bottom: 10),
|
||||
child: Icon(Icons.person_search, size: 80, color: Colors.grey,))),
|
||||
const Center(child: Text("WELCOME ON OPENCLOUD", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600,
|
||||
color: Color.fromRGBO(38, 166, 154, 1)),)),
|
||||
Padding(padding: const EdgeInsets.symmetric(vertical: 20), child: Divider(color: Colors.grey.shade300,),),
|
||||
Container( margin: const EdgeInsets.only(bottom: 10), child: Center(child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
return KeyboardListener(focusNode: focusNode,
|
||||
onKeyEvent: (value) async {
|
||||
if (value is KeyDownEvent && value.logicalKey == LogicalKeyboardKey.enter) {
|
||||
if (usernameCtrl.text == "" || passwordCtrl.text == "") { return; }
|
||||
error = null;
|
||||
setState(() {
|
||||
loading = true;
|
||||
});
|
||||
await AuthService.login(usernameCtrl.text, passwordCtrl.text).catchError( (e) {
|
||||
setState(() {
|
||||
loading = false;
|
||||
error = "Invalid username or password";
|
||||
});
|
||||
}).then( (e) {
|
||||
if (error == null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
loginIsSet = false;
|
||||
dash.inDialog = false;
|
||||
context.pop();
|
||||
mainKey?.currentState?.setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Container( padding: const EdgeInsets.all(50), child: Column(children: [
|
||||
getMainHeight(context) < 600 ? Container() : SizedBox( width: getMainWidth(context) / 4, height: getMainHeight(context) / 4,
|
||||
child: FittedBox(
|
||||
child:const Center(child: Icon(Icons.person_search, size: 150, color: Colors.grey,)))),
|
||||
Center(child: Padding( padding: const EdgeInsets.only(top: 5, bottom: 20),
|
||||
child: Text("WELCOME ON OPENCLOUD", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600,
|
||||
color: lightColor ), overflow: TextOverflow.ellipsis, ))),
|
||||
Container( margin: const EdgeInsets.only(bottom: 10),
|
||||
child: Center(child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width / 3,
|
||||
alignment : Alignment.center,
|
||||
child: TextField(
|
||||
controller: usernameCtrl,
|
||||
onChanged: (v) => setState(() {}),
|
||||
decoration: InputDecoration(
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero),
|
||||
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero),
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero),
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero),
|
||||
border: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero),
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero),
|
||||
hintText: "username...",
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
fillColor: Colors.grey.shade300,
|
||||
fillColor: midColor,
|
||||
filled: true,
|
||||
hintStyle: const TextStyle(fontSize: 12.5, color: Colors.grey)),
|
||||
style: const TextStyle(fontSize: 12.5, color: Colors.grey)),),
|
||||
style: const TextStyle(fontSize: 12.5, color: Colors.black)),),
|
||||
Container(width: 50, height: 50, color: Colors.black, child: const Icon(Icons.person, color: Colors.white))
|
||||
]))),
|
||||
Container( margin: const EdgeInsets.only(bottom: 20), child: Center(child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
Center(child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width / 3,
|
||||
alignment : Alignment.center,
|
||||
child: TextField(
|
||||
controller: passwordCtrl,
|
||||
obscureText: true,
|
||||
onChanged: (value) {
|
||||
setState(() {});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero),
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero),
|
||||
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero),
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero),
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero),
|
||||
border: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero),
|
||||
hintText: "password...",
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
fillColor: Colors.grey.shade300,
|
||||
fillColor: midColor,
|
||||
filled: true,
|
||||
hintStyle: const TextStyle(fontSize: 12.5, color: Colors.grey)),
|
||||
style: const TextStyle(fontSize: 12.5, color: Colors.grey)),),
|
||||
style: const TextStyle(fontSize: 12.5, color: Colors.black)),),
|
||||
Container(width: 50, height: 50, color: Colors.black, child: const Icon(Icons.password, color: Colors.white))
|
||||
]))),
|
||||
Row( mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Padding( padding: const EdgeInsets.only(right: 10), child:
|
||||
InkWell(onTap: () { context.pop(); },
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
width: MediaQuery.of(context).size.width / 3,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
color: const Color.fromRGBO(38, 166, 154, 1),
|
||||
child: const Center( child: Text("LOGIN", style: TextStyle(color: Colors.white, fontSize: 15),))))),
|
||||
])
|
||||
])),
|
||||
Column( children: [
|
||||
Center( child: Padding( padding: EdgeInsets.only(bottom: 10, top: error == null ? 27 : 10), child:
|
||||
error == null ? Container() : Text(error ?? "", style: TextStyle(color: redColor, fontSize: 12.5)))),
|
||||
Row( mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Padding( padding: const EdgeInsets.only(right: 10, bottom: 30), child:
|
||||
InkWell(onTap: () async {
|
||||
if (usernameCtrl.text == "" || passwordCtrl.text == "") { return; }
|
||||
error = null;
|
||||
setState(() {
|
||||
loading = true;
|
||||
});
|
||||
await AuthService.login(usernameCtrl.text, passwordCtrl.text).catchError( (e) {
|
||||
setState(() {
|
||||
loading = false;
|
||||
error = "Invalid username or password";
|
||||
});
|
||||
}).then( (e) {
|
||||
if (error == null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
loginIsSet = false;
|
||||
dash.inDialog = false;
|
||||
context.pop();
|
||||
mainKey?.currentState?.setState(() {});
|
||||
}
|
||||
});
|
||||
},
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width / 3,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
color: usernameCtrl.text == "" || passwordCtrl.text == "" ? Colors.grey : lightColor,
|
||||
child: Center( child: loading ? SpinKitWave(color: Colors.white, size: 20) : Text("LOGIN", style: TextStyle(
|
||||
color: usernameCtrl.text == "" || passwordCtrl.text == "" ? midColor :Colors.white,
|
||||
fontSize: 15) ))))),
|
||||
])
|
||||
]),
|
||||
],)));
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
|
||||
abstract class New {
|
||||
String name = "";
|
||||
}
|
||||
|
||||
class NewBoxWidget<T extends SerializerDeserializer<dynamic>> extends StatefulWidget {
|
||||
String? _selected;
|
||||
Dashboard dash;
|
||||
final TextEditingController _ctrl = TextEditingController();
|
||||
AbstractService<T> service;
|
||||
Function validate = () {};
|
||||
NewBoxWidget ({ super.key, required this.service, required this.dash, this.getItems });
|
||||
@override NewBoxWidgetState<T> createState() => NewBoxWidgetState<T>();
|
||||
|
||||
List<DropdownMenuItem> Function(APIResponse<T>? data)? getItems;
|
||||
}
|
||||
class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State<NewBoxWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
widget._ctrl.value = TextEditingValue(text: widget.dash.defaultName);
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children : [
|
||||
FutureBuilder<APIResponse<T>>(
|
||||
future: (widget.service as AbstractService<T>).all(context),
|
||||
builder: (context, snapshot) {
|
||||
List<DropdownMenuItem> items = widget.getItems != null ? widget.getItems!(snapshot.data) : [];
|
||||
if (widget._selected != null
|
||||
&& !items.where((element) => element.value == widget._selected).isNotEmpty) {
|
||||
items.add(DropdownMenuItem<String>(
|
||||
value: widget._selected.toString(),
|
||||
child: Text(widget._selected.toString()),
|
||||
));
|
||||
}
|
||||
return SizedBox( width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, height: 50,
|
||||
child: DropdownButtonFormField(
|
||||
value: widget._selected,
|
||||
isExpanded: true,
|
||||
hint: const Text("load workflow...", style: TextStyle(color: Colors.grey, fontSize: 15)),
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero,
|
||||
borderSide: BorderSide(color: Color.fromARGB(38, 166, 154, 1), width: 0),
|
||||
),
|
||||
fillColor: Colors.grey.shade300,
|
||||
contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 10, bottom: 30),
|
||||
enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.zero,
|
||||
borderSide: BorderSide(color: Colors.grey.shade300, width: 0),
|
||||
),
|
||||
border: OutlineInputBorder( borderRadius: BorderRadius.zero,
|
||||
borderSide: BorderSide(color: Colors.grey.shade300, width: 0)),
|
||||
),
|
||||
items: items, onChanged: (value) {
|
||||
setState(() {
|
||||
widget._selected = value.toString();
|
||||
});
|
||||
}));
|
||||
}),
|
||||
Tooltip(
|
||||
message: 'empty selection',
|
||||
child: InkWell(
|
||||
mouseCursor: widget._selected == null || widget._selected!.isEmpty ? MouseCursor.defer : SystemMouseCursors.click,
|
||||
onTap: () {
|
||||
if (widget._selected == null || widget._selected!.isEmpty) { return; }
|
||||
setState(() { widget._selected = null; });
|
||||
},
|
||||
child: Container(
|
||||
width: 50, height: 50,
|
||||
decoration: const BoxDecoration( color: Colors.black,
|
||||
border: Border(right: BorderSide(color: Colors.white))),
|
||||
child: Icon(Icons.refresh, color: widget._selected == null || widget._selected!.isEmpty ? Colors.grey : Colors.white),
|
||||
)
|
||||
)
|
||||
),
|
||||
Tooltip(
|
||||
message: 'load workflow selected',
|
||||
child: InkWell(
|
||||
mouseCursor: widget._selected == null || widget._selected!.isEmpty
|
||||
? MouseCursor.defer : SystemMouseCursors.click,
|
||||
onTap: () {
|
||||
if (widget._selected == null || widget._selected!.isEmpty) { return; }
|
||||
widget.dash.name = widget._selected ?? widget.dash.name;
|
||||
widget.dash.notifyListeners();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Container(
|
||||
width: 50, height: 50,
|
||||
color: Colors.black,
|
||||
child: Icon(Icons.open_in_browser_outlined,
|
||||
color: widget._selected == null || widget._selected!.isEmpty ? Colors.grey : Colors.white),
|
||||
)
|
||||
)
|
||||
)
|
||||
]),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 10),
|
||||
width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 90 : 450,
|
||||
height: 50,
|
||||
child: TextFormField(
|
||||
expands: true,
|
||||
maxLines: null,
|
||||
minLines: null,
|
||||
cursorColor: const Color.fromARGB(38, 166, 154, 1),
|
||||
controller: widget._ctrl,
|
||||
onChanged: (value) => setState(() { widget._ctrl.value = TextEditingValue(text: value); }),
|
||||
validator: (value) => value == null || value.isEmpty ? "name is required" : null,
|
||||
decoration: InputDecoration(
|
||||
hintText: "name a new workflow...",
|
||||
fillColor: Colors.grey.shade300,
|
||||
filled: true,
|
||||
contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 15, bottom: 5),
|
||||
hintStyle: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w300
|
||||
),
|
||||
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) {
|
||||
await widget.service.post(context, {}, { "workflowName" : widget._ctrl.value.text });
|
||||
widget._selected = widget._ctrl.value.text;
|
||||
widget._ctrl.value = const TextEditingValue(text: "");
|
||||
widget.dash.name = widget._selected ?? widget.dash.name;
|
||||
widget.dash.notifyListeners();
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 10),
|
||||
width: 50,
|
||||
height: 50,
|
||||
color: Colors.black,
|
||||
child: Icon(Icons.add, color: widget._ctrl.value.text.isEmpty ? Colors.grey : Colors.white)
|
||||
)
|
||||
)
|
||||
)
|
||||
])
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
107
lib/widgets/dialog/shallow_creation.dart
Normal file
107
lib/widgets/dialog/shallow_creation.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/pages/workflow.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_text_input.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ShallowCreationDialogWidget extends StatefulWidget {
|
||||
GlobalKey<ShallowTextInputWidgetState>? formKey;
|
||||
BuildContext context;
|
||||
bool Function()? canClose;
|
||||
CollaborativeAreaType type = CollaborativeAreaType.workspace;
|
||||
Future<List<Shallow>> Function()? all;
|
||||
Future<void> Function(String)? load;
|
||||
Future<void> Function(Map<String,dynamic>)? create;
|
||||
bool Function(String?)? canLoad;
|
||||
DropdownMenuItem Function(Shallow)? maptoDropdown;
|
||||
List<ShallowTextInputWidget> form = [];
|
||||
|
||||
ShallowCreationDialogWidget ({ super.key, required this.type, required this.all, this.load, this.formKey,
|
||||
required this.create, this.form = const [], this.maptoDropdown, required this.context, this.canClose }) ;
|
||||
@override ShallowCreationDialogState createState() => ShallowCreationDialogState();
|
||||
}
|
||||
class ShallowCreationDialogState extends State<ShallowCreationDialogWidget> {
|
||||
GlobalKey<FormFieldState> key = GlobalKey<FormFieldState>();
|
||||
GlobalKey<FormFieldState> key2 = GlobalKey<FormFieldState>();
|
||||
@override Widget build(BuildContext context) {
|
||||
var t = widget.type == CollaborativeAreaType.workspace ? "workspace" : (widget.type == CollaborativeAreaType.workflow ? "workflow" : (widget.type == CollaborativeAreaType.collaborative_area ? "collaborative area" :"peer"));
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.only( top: 0, bottom: 20, left: 20, right: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.centerRight,
|
||||
height: 50,
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [
|
||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child:
|
||||
Text("load or create a new $t", 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: () {
|
||||
dash.inDialog = false;
|
||||
AppRouter.catalog.go(context, {});
|
||||
},
|
||||
child: const Icon(Icons.arrow_back, color: Colors.black))),
|
||||
),
|
||||
widget.canClose != null && !widget.canClose!() ? Container() : Row ( mainAxisAlignment: MainAxisAlignment.end, children: [
|
||||
Tooltip( message: "close", child: InkWell(
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () {
|
||||
dash.inDialog = false;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Icon(Icons.close, color: Colors.black))),
|
||||
]),
|
||||
],),
|
||||
),
|
||||
ShallowDropdownInputWidget(
|
||||
all: widget.all,
|
||||
type: widget.type,
|
||||
hint: "select a $t",
|
||||
width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400,
|
||||
load: (e) async {
|
||||
await widget.load!(e);
|
||||
dash.inDialog = false;
|
||||
Navigator.pop(widget.context);
|
||||
},
|
||||
iconLoad: Icons.open_in_browser_outlined,
|
||||
iconRemove: Icons.refresh,
|
||||
maptoDropdown: widget.maptoDropdown,
|
||||
canLoad: (p0) => p0 != null && p0.isNotEmpty,
|
||||
canRemove: (p0) => p0 != null && p0.isNotEmpty,
|
||||
tooltipRemove: "refresh selection",
|
||||
deletion: true,
|
||||
color: Colors.black,
|
||||
hintColor: Colors.grey,
|
||||
filled: midColor,
|
||||
),
|
||||
Container( height: 10),
|
||||
widget.create != null ? ShallowTextInputWidget(
|
||||
key: widget.formKey,
|
||||
type: widget.type,
|
||||
hint: "create a new $t",
|
||||
width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400,
|
||||
load: (e) async {
|
||||
await widget.create!(e);
|
||||
dash.inDialog = false;
|
||||
Navigator.pop(widget.context);
|
||||
},
|
||||
forms: widget.form,
|
||||
canLoad: (p0) => p0 != null && p0.isNotEmpty,
|
||||
color: Colors.black,
|
||||
hintColor: Colors.grey,
|
||||
filled: midColor,
|
||||
) : Container(),
|
||||
...(widget.create != null ? widget.form.map( (e) => Container( margin: const EdgeInsets.only(top: 10), child: e)) : []),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
105
lib/widgets/forms/container_forms.dart
Normal file
105
lib/widgets/forms/container_forms.dart
Normal file
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/widgets/forms/sub_expose_forms.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ContainerFormsWidget extends StatefulWidget {
|
||||
int instanceID = 0;
|
||||
Dashboard dash;
|
||||
AbstractItem item;
|
||||
String elementID;
|
||||
ContainerFormsWidget({ super.key, required this.item, required this.dash, required this.elementID });
|
||||
@override ContainerFormsWidgetState createState() => ContainerFormsWidgetState();
|
||||
}
|
||||
|
||||
class ContainerFormsWidgetState extends State<ContainerFormsWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
List<Widget> widgets = [];
|
||||
var instance = widget.item.getSelectedInstance();
|
||||
if (instance != null && instance is ProcessingInstance && instance.access?.container != null) {
|
||||
var container = instance.access!.container!;
|
||||
widgets.add(Container(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
width: 180,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text("<CONTAINER>", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
|
||||
SubTextInputWidget(subkey: "image", width: 180, empty: false, change: (value) { },
|
||||
initialValue: container.image, readOnly: true),
|
||||
SubTextInputWidget(subkey: "command", width: 180, empty: false, change: (value) {
|
||||
container.command = value;
|
||||
for (var el in widget.dash.elements) {
|
||||
if (el.id == widget.elementID) {
|
||||
el.element = widget.item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}, initialValue: container.command, readOnly: false,),
|
||||
SubTextInputWidget(subkey: "args", width: 180, empty: false, change: (value) {
|
||||
container.args = value;
|
||||
for (var el in widget.dash.elements) {
|
||||
if (el.id == widget.elementID) {
|
||||
el.element = widget.item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
},
|
||||
initialValue: container.args, readOnly: false,)
|
||||
],)
|
||||
));
|
||||
widgets.add(Container(
|
||||
width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))),
|
||||
));
|
||||
widgets.add(Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
width: 180,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Padding(padding: EdgeInsets.only(bottom: 5), child: Text("<EXPOSE>",
|
||||
style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center)),
|
||||
Row( children: [
|
||||
InkWell( onTap: () {
|
||||
container.exposes.add(Expose());
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
setState(() {});
|
||||
}, child:
|
||||
Container( margin: const EdgeInsets.only(top: 5),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)),
|
||||
width: 125, height: 30,
|
||||
child: const Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add)), Text("add expose")]),
|
||||
)
|
||||
),
|
||||
InkWell( onTap: () {
|
||||
if (container.exposes.isEmpty) { return; }
|
||||
container.exposes = container.exposes.sublist(0, container.exposes.length - 1);
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
setState(() {});
|
||||
}, child:
|
||||
Container( margin: const EdgeInsets.only(left: 5, top: 5),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)),
|
||||
width: 45, height: 30,
|
||||
child: const Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ Icon(Icons.delete, color: Colors.black) ]),
|
||||
)
|
||||
)
|
||||
]),
|
||||
],)
|
||||
));
|
||||
for (var expose in container.exposes) {
|
||||
widgets.add(SubExposeFormsWidget( readOnly: true, width: 180, dash: widget.dash, empty: widgets.isEmpty,
|
||||
item: expose, elementID: widget.elementID));
|
||||
}
|
||||
}
|
||||
return Column(children: widgets);
|
||||
}
|
||||
}
|
||||
58
lib/widgets/forms/credentials_forms.dart
Normal file
58
lib/widgets/forms/credentials_forms.dart
Normal file
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class CredentialsFormsWidget extends StatefulWidget {
|
||||
int instanceID = 0;
|
||||
Dashboard dash;
|
||||
AbstractItem item;
|
||||
String elementID;
|
||||
CredentialsFormsWidget({ super.key, required this.item, required this.dash, required this.elementID });
|
||||
@override CredentialsFormsWidgetState createState() => CredentialsFormsWidgetState();
|
||||
}
|
||||
|
||||
class CredentialsFormsWidgetState extends State<CredentialsFormsWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
List<Widget> widgets = [];
|
||||
var instance = widget.item.getSelectedInstance();
|
||||
if (instance != null && instance.credential != null) {
|
||||
var creds = instance.credential!;
|
||||
widgets.add(Container( margin: EdgeInsets.only(bottom: 15),
|
||||
width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))),
|
||||
));
|
||||
widgets.add(Container(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
width: 180,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text("<CREDENTIALS>", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
|
||||
SubTextInputWidget(subkey: "login", width: 180, empty: false, change: (value) {
|
||||
creds.password = value;
|
||||
for (var el in widget.dash.elements) {
|
||||
if (el.id == widget.elementID) {
|
||||
el.element = widget.item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}, initialValue: creds.login),
|
||||
SubTextInputWidget(subkey: "password", width: 180, empty: false, change: (value) {
|
||||
creds.password = value;
|
||||
for (var el in widget.dash.elements) {
|
||||
if (el.id == widget.elementID) {
|
||||
el.element = widget.item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}, initialValue: creds.password, readOnly: false,),
|
||||
],)
|
||||
));
|
||||
widgets.add(Container( padding: EdgeInsets.only(bottom: 15), width: 200 ));
|
||||
}
|
||||
return Column(children: widgets);
|
||||
}
|
||||
}
|
||||
92
lib/widgets/forms/resource_forms.dart
Normal file
92
lib/widgets/forms/resource_forms.dart
Normal file
@@ -0,0 +1,92 @@
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/core/services/perms_service.dart';
|
||||
import 'package:oc_front/widgets/forms/credentials_forms.dart';
|
||||
import 'package:oc_front/widgets/forms/sub_keys_forms.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
|
||||
import 'package:oc_front/widgets/forms/container_forms.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_dropdown_input%20.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ResourceFormsWidget extends StatefulWidget {
|
||||
AbstractItem item;
|
||||
Dashboard dash;
|
||||
String elementID;
|
||||
ResourceFormsWidget ({ super.key, required this.item, required this.dash, required this.elementID });
|
||||
@override ResourceFormsWidgetState createState() => ResourceFormsWidgetState();
|
||||
}
|
||||
|
||||
class ResourceFormsWidgetState extends State<ResourceFormsWidget> {
|
||||
List<Widget> getWidgets(Map<String, dynamic> infos) {
|
||||
List<Widget> widgets = [];
|
||||
for (var key in infos.keys) {
|
||||
if (infos[key] == null && infos[key] != 0) { continue; }
|
||||
if (infos[key] is Map) { widgets.addAll(getWidgets(infos[key]));
|
||||
} if (infos[key] is List) {
|
||||
if (infos[key].isEmpty) { continue; }
|
||||
widgets.add(SubTextInputWidget(subkey: key.replaceAll("_", " "), width: 180, empty: false, readOnly: true,
|
||||
change: (value) {}, initialValue: (infos[key] as List<dynamic>).join(",") ));
|
||||
} else if (infos[key] is Map) {
|
||||
widgets.addAll(getWidgets(infos[key] as Map<String, dynamic>));
|
||||
} else {
|
||||
widgets.add(SubTextInputWidget(subkey: key.replaceAll("_", " "), width: 180, empty: false, readOnly: true,
|
||||
change: (value) {}, initialValue: infos[key] is List ? infos[key].join(",") : "${infos[key]}" ));
|
||||
}
|
||||
}
|
||||
if (widgets.isNotEmpty) {
|
||||
widgets.add(SizedBox( width: 200, height: 15) );
|
||||
}
|
||||
return widgets;
|
||||
}
|
||||
|
||||
Widget getInputAndOutputVariableForms(bool readOnly) {
|
||||
List<Widget> res = [];
|
||||
res.add(SubKeysMapFormsWidget(dash: widget.dash, type: SubMapFormsType.INPUT, item: widget.item, elementID: widget.elementID,
|
||||
readOnly: readOnly));
|
||||
res.add(SubKeysMapFormsWidget(dash: widget.dash, type: SubMapFormsType.OUTPUT, item: widget.item, elementID: widget.elementID,
|
||||
readOnly: readOnly));
|
||||
res.add(SubKeysMapFormsWidget(dash: widget.dash, type: SubMapFormsType.ENV, item: widget.item, elementID: widget.elementID,
|
||||
readOnly: readOnly));
|
||||
return Column( children: res );
|
||||
}
|
||||
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
List<Widget> instancesCat = [];
|
||||
List<Widget> childrenReadOnly = getWidgets(widget.item.infos());
|
||||
List<DropdownMenuItem<String>> dpItems = [];
|
||||
for (var (i, instance) in widget.item.instances.indexed) {
|
||||
dpItems.add(DropdownMenuItem(value: '$i', child: Text('${instance.name}', overflow: TextOverflow.ellipsis,)));
|
||||
}
|
||||
if (dpItems.isNotEmpty) {
|
||||
childrenReadOnly.add(Padding( padding: EdgeInsets.only(top: 20),
|
||||
child : Container(
|
||||
width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))),
|
||||
)));
|
||||
childrenReadOnly.add(Padding(padding: EdgeInsets.only(bottom: 15), child:
|
||||
SubDropdownInputWidget( dropdownMenuEntries: dpItems, subkey: "", width: 180, empty: false,
|
||||
initialValue: "${widget.item.selectedInstance}", change: (value) {
|
||||
if (value != null) { setState(() { widget.item.selectedInstance = int.parse(value); }); }
|
||||
},
|
||||
))
|
||||
);
|
||||
if (widget.item.instances.length > (widget.item.selectedInstance)) {
|
||||
childrenReadOnly.addAll(getWidgets(widget.item.instances[(widget.item.selectedInstance)].infos()));
|
||||
}
|
||||
}
|
||||
instancesCat.add(ContainerFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID));
|
||||
instancesCat.add(CredentialsFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID));
|
||||
if (instancesCat.isNotEmpty) {
|
||||
instancesCat.add(Container(
|
||||
width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))),
|
||||
));
|
||||
}
|
||||
bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT);
|
||||
// missing env input and output variables
|
||||
return SizedBox( height: getHeight(context) - 330, child: SingleChildScrollView( child: Column(
|
||||
children: [ getInputAndOutputVariableForms(readOnly), ...childrenReadOnly, ...instancesCat, ])));
|
||||
}
|
||||
}
|
||||
554
lib/widgets/forms/scheduler_forms.dart
Normal file
554
lib/widgets/forms/scheduler_forms.dart
Normal file
@@ -0,0 +1,554 @@
|
||||
|
||||
import 'package:cron/cron.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_scheduler_service.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'package:alert_banner/exports.dart';
|
||||
import 'package:oc_front/models/resources/compute.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/pages/workflow.dart';
|
||||
import 'package:oc_front/widgets/dialog/alert.dart';
|
||||
import 'package:oc_front/widgets/dialog/confirm_box.dart';
|
||||
import 'package:oc_front/core/services/perms_service.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_text_input.dart';
|
||||
import 'package:oc_front/core/models/shared_workspace_local.dart';
|
||||
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/check_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_service.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class SchedulerFormsWidget extends StatefulWidget {
|
||||
Scheduler schedule = Scheduler();
|
||||
Dashboard item;
|
||||
bool? booking;
|
||||
bool valid = false;
|
||||
bool shouldSearch = true;
|
||||
int scheduleFutureCount = 0;
|
||||
int scheduleBeforeCount = 0;
|
||||
String? error;
|
||||
String? errorEndDate;
|
||||
String? errorCron;
|
||||
Function validate = () {};
|
||||
final SchedulerService _schedulerService = SchedulerService();
|
||||
final WorkflowExecutionService _executionService = WorkflowExecutionService();
|
||||
SchedulerFormsWidget ({ super.key, required this.item, });
|
||||
@override SchedulerFormsWidgetState createState() => SchedulerFormsWidgetState();
|
||||
}
|
||||
class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
|
||||
CheckService check = CheckService();
|
||||
void save(List<GlobalKey<FormFieldState>> formKeys) {
|
||||
print("save");
|
||||
widget.error = null;
|
||||
widget.errorEndDate = null;
|
||||
widget.errorCron = null;
|
||||
if (dash.elements.isEmpty || dash.elements.where((element) => element.element is ProcessingItem).isEmpty) {
|
||||
dash.error = "You need at least one processing element";
|
||||
}
|
||||
var processings = dash.elements.where((element) => element.element is ProcessingItem);
|
||||
var computes = dash.elements.where((element) => element.element is ComputeItem);
|
||||
for (var p in processings) {
|
||||
var links = dash.arrows.where((element) => element.fromID.contains(p.id) || element.toID.contains(p.id));
|
||||
try {
|
||||
List<ComputeItem> c = [];
|
||||
for (var link in links) {
|
||||
c.addAll(computes.where( (e) => link.toID.contains(e.id) || link.fromID.contains(e.id)).map( (e) => e.element as ComputeItem));
|
||||
}
|
||||
if (c.isEmpty) { throw Exception("no compute element linked"); }
|
||||
} catch (e) {
|
||||
dash.error = "You need to link each processing element to a compute element";
|
||||
}
|
||||
}
|
||||
if (dash.error != null) {
|
||||
showAlertBanner( context, () {}, AlertAlertBannerChild(text: dash.error.toString()),// <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
setState(() {});
|
||||
return;
|
||||
}
|
||||
for (var k in formKeys) {
|
||||
if (k.currentState != null) {
|
||||
if (!k.currentState!.validate()) {
|
||||
return;
|
||||
} else { k.currentState!.save();}
|
||||
}
|
||||
}
|
||||
DateTime now = DateTime.now().add(const Duration(minutes: 1));
|
||||
if (widget.schedule.start == null || widget.schedule.start!.isBefore(now)) {
|
||||
widget.schedule.start = now.toUtc();
|
||||
if (widget.schedule.end != null) {
|
||||
widget.schedule.end = now.add(const Duration(minutes: 1)).toUtc();
|
||||
}
|
||||
}
|
||||
Duration durationBefore = widget.schedule.start!.difference(DateTime.now().toUtc()) + Duration(seconds: 5);
|
||||
widget._schedulerService.schedule(context, widget.item.id ?? "", widget.schedule.serialize(), {}).then((value) {
|
||||
setState(() { widget.valid = true; });
|
||||
Future.delayed(durationBefore, () {
|
||||
try {
|
||||
setState(() {});
|
||||
} catch (e) { /* */ }
|
||||
});
|
||||
Future.delayed(const Duration(seconds: 10), () {
|
||||
try {
|
||||
setState(() { widget.valid = false; });
|
||||
} catch (e) { /* */ }
|
||||
});
|
||||
});
|
||||
}
|
||||
void checkBooking(List<GlobalKey<FormFieldState>> formKeys, void Function(List<GlobalKey<FormFieldState>> )? f){
|
||||
if (widget.schedule.start == null) {
|
||||
DateTime now = DateTime.now().add(const Duration(minutes: 5));
|
||||
widget.schedule.start = now.toUtc();
|
||||
}
|
||||
var s = widget.schedule.start!.toUtc().toIso8601String();
|
||||
var e = "";
|
||||
if (widget.schedule.end == null) {
|
||||
e = widget.schedule.start!.add(const Duration(seconds: 5)).toUtc().toIso8601String();
|
||||
} else {
|
||||
e = widget.schedule.end!.toUtc().toIso8601String();
|
||||
}
|
||||
check.search(context, [widget.item.id ?? "", s.substring(0, 19), e.substring(0, 19)], {}).then(
|
||||
(v) {
|
||||
if (v.data == null) { return; }
|
||||
widget.booking = v.data!.isAvailable;
|
||||
if (v.data!.isAvailable) {
|
||||
if (f != null) { f(formKeys);
|
||||
} else {
|
||||
showAlertBanner( context, () {},
|
||||
const InfoAlertBannerChild(text: "no booking found at this date"),// <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
}
|
||||
} else {
|
||||
showAlertBanner( context, () {},
|
||||
const AlertAlertBannerChild(text: "booking found at this date"),// <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
if (widget.shouldSearch && widget.item.name != "") {
|
||||
widget.shouldSearch = false;
|
||||
widget._executionService.search(null, [widget.item.name], {}).then((value) {
|
||||
if (value.data != null) {
|
||||
try {
|
||||
setState(() {
|
||||
widget.scheduleFutureCount = 0;
|
||||
widget.scheduleBeforeCount = 0;
|
||||
for (var exec in value.data!.executions) {
|
||||
if (exec.startDate != null && DateTime.parse(exec.startDate!).isAfter(DateTime.now().toUtc())) {
|
||||
widget.scheduleFutureCount++;
|
||||
} else {
|
||||
widget.scheduleBeforeCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) { /* */ }
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
widget.shouldSearch = true;
|
||||
});
|
||||
}
|
||||
bool isService = true;
|
||||
try {
|
||||
widget.item.elements.firstWhere((element) => (element.element?.serialize()["is_service"] ?? false) == true);
|
||||
} catch (e) {
|
||||
isService = false;
|
||||
}
|
||||
bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT);
|
||||
DateTime? start;
|
||||
DateTime? end;
|
||||
|
||||
Duration delayed = const Duration(minutes: 5);
|
||||
if (widget.schedule.start != null) {
|
||||
start = widget.schedule.start!;
|
||||
if (start.isBefore(DateTime.now())) {
|
||||
start = DateTime.now().add(const Duration(minutes: 5));
|
||||
widget.schedule.start = start.toUtc();
|
||||
}
|
||||
if (start.isBefore(DateTime.now())) {
|
||||
// get difference between now and start
|
||||
delayed = start.difference(DateTime.now());
|
||||
}
|
||||
}
|
||||
if (widget.schedule.end != null) {
|
||||
end = widget.schedule.end!;
|
||||
if (end.isBefore(DateTime.now())) {
|
||||
end = DateTime.now().add(const Duration(minutes: 5));
|
||||
widget.schedule.end = end.toUtc();
|
||||
}
|
||||
if (end.isBefore(DateTime.now())) {
|
||||
// get difference between now and start
|
||||
delayed = end.difference(DateTime.now());
|
||||
Future.delayed(delayed, () {
|
||||
WorkflowFactory.key.currentState?.setState(() { });
|
||||
});
|
||||
}
|
||||
}
|
||||
List<GlobalKey<FormFieldState>> formKeys = [GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>()];
|
||||
var shallow = ShallowTextInputWidget(
|
||||
width: 200 - 1, readOnly: readOnly,
|
||||
current: widget.item.name,
|
||||
type: CollaborativeAreaType.workflow,
|
||||
canRemove: PermsService.getPerm(Perms.WORKFLOW_DELETE) ? (p0) => p0 != null && p0.isNotEmpty : null,
|
||||
remove: PermsService.getPerm(Perms.WORKFLOW_DELETE) ? (p0) async {
|
||||
showDialog(context: context, builder: (context) {
|
||||
return ConfirmBoxWidget(
|
||||
purpose: "Are you sure you want to delete this workflow?",
|
||||
validate: () async {
|
||||
await WorflowService().delete(context, widget.item.id ?? "", {}).then((value) {
|
||||
dash.id = null;
|
||||
dash.name = "";
|
||||
dash.isOpened = false;
|
||||
dash.clear();
|
||||
dash.chartKey.currentState?.widget.flowChart.setState(() { });
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
} : null,
|
||||
);
|
||||
shallow.change =(p0) => Future.delayed( const Duration(seconds: 2), () async {
|
||||
if (shallow.compare == p0) {
|
||||
await WorflowService().put(context, widget.item.id ?? "", { "name" : p0 }, {});
|
||||
} else {
|
||||
shallow.compare = p0;
|
||||
}
|
||||
});
|
||||
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),
|
||||
])),
|
||||
widget.item.name == "" ? Container() : Container(
|
||||
decoration: BoxDecoration( border: Border(
|
||||
left: BorderSide(color: midColor, width: 1),
|
||||
bottom: const BorderSide(color: Colors.grey))),
|
||||
child: shallow ),
|
||||
const SizedBox(height: 20, width: 200 ),
|
||||
isService ? Text("Warning a processing is a service, if no end execution it will run forever.") : Container(),
|
||||
Tooltip( message: "start executions",
|
||||
child: Container( height: 40, margin: const EdgeInsets.only(top: 5),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
||||
child: DateTimeField( key: formKeys[1],
|
||||
enabled: !readOnly,
|
||||
resetIcon: null,
|
||||
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: midColor,
|
||||
tertiary: Colors.grey,
|
||||
secondary: Colors.grey,
|
||||
primary: Colors.black),
|
||||
),
|
||||
child: child ?? Container(),
|
||||
);
|
||||
return w;
|
||||
},
|
||||
context: context,
|
||||
firstDate: DateTime.now().add(const Duration(minutes: 5)),
|
||||
initialDate: DateTime.parse( start?.toLocal().toIso8601String()
|
||||
?? currentValue?.toIso8601String()
|
||||
?? DateTime.now().add(const Duration(minutes: 5)).toUtc().toIso8601String()).toLocal(),
|
||||
lastDate: DateTime(2100)
|
||||
);
|
||||
if (date != null) {
|
||||
TimeOfDay? time;
|
||||
var count = 0;
|
||||
while(date!.microsecondsSinceEpoch <= (DateTime.now().microsecondsSinceEpoch) || time == null) {
|
||||
if (count > 0) {
|
||||
showAlertBanner( context, () {},
|
||||
const AlertAlertBannerChild(
|
||||
text: "must be at least 1 minute from now to let system check info"),// <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
}
|
||||
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: midColor,
|
||||
tertiary: Colors.grey,
|
||||
secondary: Colors.grey,
|
||||
primary: Colors.black),
|
||||
),
|
||||
child: child ?? Container(),
|
||||
);
|
||||
return w;
|
||||
},
|
||||
);
|
||||
if (time == null) { return DateTime.now().add( const Duration(minutes: 1)); }
|
||||
count++;
|
||||
date = DateTime(date.year, date.month, date.day, time.hour, time.minute);
|
||||
widget.schedule.start = date.toUtc();
|
||||
}
|
||||
widget.item.saveDash(widget.item.id, context);
|
||||
}
|
||||
return date;
|
||||
},
|
||||
format: intl.DateFormat('y-M-dd HH:mm:ss'),
|
||||
initialValue: start?.toLocal() ?? DateTime.now(),
|
||||
onChanged: (value) { },
|
||||
validator: (value) {
|
||||
return 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 executions...",
|
||||
labelText: "start executions*",
|
||||
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 executions",
|
||||
child: Container( height: 40, margin: const EdgeInsets.only(top: 5),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
||||
child: DateTimeField( key: formKeys[2],
|
||||
enabled: !readOnly,
|
||||
validator: (value) {
|
||||
if (value == null && widget.schedule.cron != null && widget.schedule.cron!.isNotEmpty) {
|
||||
setState(() {
|
||||
widget.errorEndDate = 'missing start date';
|
||||
});
|
||||
}
|
||||
return value == null && widget.schedule.cron != null && widget.schedule.cron!.isNotEmpty ? "not empty" : null;
|
||||
},
|
||||
onChanged: (value) {
|
||||
if (value == null) {
|
||||
widget.schedule.end = 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: midColor,
|
||||
tertiary: Colors.grey,
|
||||
secondary: Colors.grey,
|
||||
primary: Colors.black),
|
||||
),
|
||||
child: child ?? Container(),
|
||||
);
|
||||
return w;
|
||||
},
|
||||
context: context,
|
||||
firstDate: DateTime.now().add(const Duration(minutes: 5)),
|
||||
initialDate: DateTime.parse( end?.toLocal().toIso8601String()
|
||||
?? currentValue?.toIso8601String()
|
||||
?? DateTime.now().add(const Duration(minutes: 5)).toUtc().toIso8601String()).toLocal(),
|
||||
lastDate: DateTime(2100)
|
||||
);
|
||||
if (date != null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
date = DateTime(date.year, date.month, date.day, date.hour, date.minute);
|
||||
TimeOfDay? time;
|
||||
var count = 0;
|
||||
while(date!.microsecondsSinceEpoch <= (DateTime.now().microsecondsSinceEpoch)
|
||||
|| time == null
|
||||
|| (date.microsecondsSinceEpoch) <= (widget.schedule.start ?? DateTime.now()).microsecondsSinceEpoch) {
|
||||
if (count > 0) {
|
||||
showAlertBanner( context, () {}, // ignore: use_build_context_synchronously
|
||||
const AlertAlertBannerChild(text: "must be at least 1 minute from now to let system check info && upper starting date"),// <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
}
|
||||
// ignore: use_build_context_synchronously
|
||||
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: midColor,
|
||||
tertiary: Colors.grey,
|
||||
secondary: Colors.grey,
|
||||
primary: Colors.black),
|
||||
),
|
||||
child: child ?? Container(),
|
||||
);
|
||||
return w;
|
||||
},
|
||||
);
|
||||
if (time == null) { return null; }
|
||||
count++;
|
||||
date = DateTime(date.year, date.month, date.day, time.hour, time.minute);
|
||||
widget.schedule.end = date.toUtc();
|
||||
}
|
||||
widget.item.saveDash(widget.item.id, context);
|
||||
}
|
||||
return date;
|
||||
},
|
||||
format: intl.DateFormat('y-M-dd HH:mm:ss'),
|
||||
initialValue: end?.toLocal(),
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
fillColor: Colors.white,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
filled: true,
|
||||
alignLabelWithHint: false,
|
||||
hintText: "enter end executions...",
|
||||
labelText: "end executions",
|
||||
hintStyle: const TextStyle(fontSize: 10),
|
||||
labelStyle: const TextStyle(fontSize: 10),
|
||||
focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.black)),
|
||||
errorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.black)),
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.black)),
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.grey)),
|
||||
border: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.grey)),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
),
|
||||
))),
|
||||
Tooltip( message: "cron command",
|
||||
child: Container( height: 40, margin: const EdgeInsets.only(top: 5),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
||||
child: TextFormField( key: formKeys[3],
|
||||
enabled: !readOnly,
|
||||
initialValue: widget.schedule.cron,
|
||||
onChanged: (value) {
|
||||
Future.delayed(const Duration(seconds: 100), () {
|
||||
if (widget.schedule.cron == value) {
|
||||
widget.item.saveDash(widget.item.id, context);
|
||||
}
|
||||
});
|
||||
widget.schedule.cron = value;
|
||||
},
|
||||
onSaved: (value) {
|
||||
if (value != null) {
|
||||
widget.schedule.cron = value;
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
var cron = Cron();
|
||||
if (value != null && value.isNotEmpty) {
|
||||
try {
|
||||
cron.schedule(Schedule.parse(value), () {});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
widget.errorCron = e.toString();
|
||||
});
|
||||
return "invalid cron";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
hintText: "enter cron command...",
|
||||
labelText: "cron",
|
||||
errorStyle: TextStyle(height: 0),
|
||||
hintStyle: TextStyle(fontSize: 10),
|
||||
labelStyle: TextStyle(fontSize: 10),
|
||||
focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.black)),
|
||||
errorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.black)),
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.black)),
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.grey)),
|
||||
border: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.grey)),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
),
|
||||
))),
|
||||
Container(
|
||||
width: 200,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(border: Border(bottom: BorderSide(color:
|
||||
PermsService.getPerm(Perms.WORKFLOW_BOOKING)? Colors.grey : Colors.transparent, width: 1))),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 200,
|
||||
height: 10,
|
||||
),
|
||||
PermsService.getPerm(Perms.WORKFLOW_BOOKING)? Tooltip( message: "check booking", child: InkWell( mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () { PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? checkBooking(formKeys, null) : null;
|
||||
}, child: Container( margin: const EdgeInsets.only(bottom: 5, left: 10, right: 10),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: widget.booking == null ? (
|
||||
PermsService.getPerm(Perms.WORKFLOW_BOOKING) && PermsService.getPerm(Perms.WORKFLOW_EDIT) ? Colors.black : Colors.grey) : (
|
||||
widget.booking == true ? Colors.green : redColor), width: 1)),
|
||||
width: 200, height: 30,
|
||||
child: Icon( Icons.verified_outlined,
|
||||
color: widget.booking == null ? Colors.black : (widget.booking == true ? Colors.green : redColor)),
|
||||
))
|
||||
): Container(),
|
||||
PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? Tooltip( message: "book", child: InkWell( mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () {
|
||||
setState(() { save(formKeys); });
|
||||
}, child: Container( margin: const EdgeInsets.only(top: 5, bottom: 10, left: 10, right: 10),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: dash.error != null ? Colors.red : ( PermsService.getPerm(Perms.WORKFLOW_BOOKING) ?(widget.valid ? Colors.green : Colors.black) : Colors.grey ))),
|
||||
width: 200, height: 30,
|
||||
child: Icon(Icons.schedule_send, color: dash.error != null ? Colors.red : (widget.valid ? Colors.green : Colors.black)),
|
||||
))
|
||||
) : Container(),
|
||||
Column( children: [
|
||||
Container(
|
||||
height: 15, width: 200,
|
||||
decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.grey))),
|
||||
),
|
||||
Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 13, color: Colors.grey ),
|
||||
"Was booked ${widget.scheduleBeforeCount} times.")),
|
||||
Container( alignment: Alignment.center, padding: const EdgeInsets.only(left: 10, right: 10, bottom: 15),
|
||||
child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 13, color: Colors.grey ),
|
||||
"Is booked ${widget.scheduleFutureCount} times.")),
|
||||
]),
|
||||
widget.item.info["shared"] != null && (widget.item.info["shared"] as List<dynamic>).isNotEmpty ? Column( children: [
|
||||
Container(
|
||||
height: 30,
|
||||
width: 200,
|
||||
decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.grey))),
|
||||
),
|
||||
Container( alignment: Alignment.center,
|
||||
child:Text( overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold),
|
||||
"Is shared ${(widget.item.info["shared"] as List<dynamic>).length} time(s).")),
|
||||
...(widget.item.info["shared"] as List<dynamic>).where( (e) => CollaborativeAreaLocal.getCollaborativeArea(e) != null
|
||||
).map((e) {
|
||||
var sw = CollaborativeAreaLocal.getCollaborativeArea(e);
|
||||
return Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: Row( children: [
|
||||
const Padding(padding: EdgeInsets.only( left: 10, right: 10), child: Icon(Icons.work, color: Colors.grey, size: 15)),
|
||||
Text(style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||
"Workspace: ${sw != null && sw.name != null ?
|
||||
"${sw.name!.substring(0, sw.name!.length > 15 ? 12 : sw.name!.length)}${sw.name!.length > 15 ? "..." : ""}" : ""}") ]));
|
||||
},)
|
||||
]) : Container()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
154
lib/widgets/forms/storage_processing_link_forms.dart
Normal file
154
lib/widgets/forms/storage_processing_link_forms.dart
Normal file
@@ -0,0 +1,154 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_advanced_switch/flutter_advanced_switch.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class StorageProcessingLinkFormsWidget extends StatefulWidget {
|
||||
Dashboard dash;
|
||||
ArrowPainter item;
|
||||
bool readOnly = false;
|
||||
StorageProcessingLinkFormsWidget ({ super.key, required this.dash, required this.item, this.readOnly = false });
|
||||
@override StorageProcessingLinkFormsWidgetState createState() => StorageProcessingLinkFormsWidgetState();
|
||||
}
|
||||
|
||||
class StorageProcessingLinkFormsWidgetState extends State<StorageProcessingLinkFormsWidget> {
|
||||
|
||||
List<Param> getParams(String fromID, String toID) {
|
||||
List<Param> arr = [];
|
||||
var els = widget.dash.elements.where( (e) => fromID.contains(e.id) || toID.contains(e.id));
|
||||
for (var element in els) {
|
||||
var g = GraphItem();
|
||||
g.fromDashboard(element.serialize());
|
||||
var e = g.getElement();
|
||||
if (e == null) { continue; }
|
||||
if (e.getSelectedInstance() != null) {
|
||||
for (var env in e.getSelectedInstance()!.env) {
|
||||
if (env.name?.contains("LINK") ?? true) { continue; }
|
||||
arr.add(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr.where( (e) => e.name != null && e.value != null).toList();
|
||||
}
|
||||
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
List<Widget> children = [
|
||||
Padding( padding: const EdgeInsets.only(top: 10),
|
||||
child: Text("<ENV VARIABLES>",
|
||||
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center)),
|
||||
];
|
||||
var params = getParams(widget.item.fromID, widget.item.toID);
|
||||
widget.item.env = params.map( (e) => e.serialize()).toList();
|
||||
for (var param in params) {
|
||||
children.add(SubTextInputWidget(subkey: param.name ?? "", width: 180, empty: false, readOnly: true,
|
||||
change: (value) {}, initialValue: param.value ?? "", copyLabel: true));
|
||||
}
|
||||
children.add(Container(width: 200, padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1)))));
|
||||
List<Widget> inf = [];
|
||||
int count = 0;
|
||||
for(var info in widget.item.infos) {
|
||||
count++;
|
||||
inf.add(Padding( padding: EdgeInsets.only(top: 10, bottom: 5),
|
||||
child : Row( crossAxisAlignment: CrossAxisAlignment.center, children: [
|
||||
Padding(padding: EdgeInsets.only(left: 10, right: 10), child: Text("N°$count")),
|
||||
Container(width: 140, decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))))
|
||||
])));
|
||||
for (var key in (info as Map<String, dynamic>).keys) {
|
||||
if (info[key] is bool) {
|
||||
inf.add(AdvancedSwitch(
|
||||
width: 150.0,
|
||||
height: 25.0,
|
||||
initialValue: info[key] as bool? ?? false,
|
||||
enabled: !widget.readOnly,
|
||||
activeChild: Text(key, style: const TextStyle(color: Colors.white)),
|
||||
inactiveChild: Text(key == "write" ? "read" : "no $key", style: const TextStyle(color: Colors.white)),
|
||||
activeColor: Colors.green,
|
||||
inactiveColor: redColor,
|
||||
onChanged: (v) {
|
||||
try {
|
||||
info[key] = v;
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
for (var a in widget.dash.arrows) {
|
||||
if (a.fromID == widget.item.fromID && a.toID == widget.item.toID) {
|
||||
a.infos = widget.item.infos;
|
||||
}
|
||||
}
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
});
|
||||
} catch (e) { /* */ }
|
||||
|
||||
},
|
||||
));
|
||||
} else if (info[key] is String?) {
|
||||
inf.add(SubTextInputWidget(subkey: key, width: 180, empty: false, change: (v) {
|
||||
try {
|
||||
info[key] = v;
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
if (info[key] != v) { return; }
|
||||
for (var a in widget.dash.arrows) {
|
||||
if (a.fromID == widget.item.fromID && a.toID == widget.item.toID) {
|
||||
a.infos = widget.item.infos;
|
||||
}
|
||||
}
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
});
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
}, initialValue: "${info[key] ?? ""}", readOnly: false, noLabel: false));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return SizedBox( height: getHeight(context) - 230, child: SingleChildScrollView( child: Column(children: [
|
||||
...children,
|
||||
Row( mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
InkWell( onTap: () {
|
||||
widget.item.infos.add({
|
||||
"write": false,
|
||||
"source": null,
|
||||
"destination": null,
|
||||
"filename": null,
|
||||
});
|
||||
setState(() {
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
});
|
||||
}, child: Container( margin: const EdgeInsets.only(top: 10),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: Colors.grey, width: 1)),
|
||||
width: 125, height: 30,
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add, color: Colors.black,)),
|
||||
Text("link infos",
|
||||
style: TextStyle( color: Colors.black))]),
|
||||
),
|
||||
),
|
||||
InkWell( onTap: () {
|
||||
if (widget.item.infos.isEmpty) { return; }
|
||||
setState(() {
|
||||
widget.item.infos.removeLast();
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
});
|
||||
}, child:
|
||||
Container( margin: const EdgeInsets.only(left: 5, top: 10),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: widget.item.infos.isEmpty ? Colors.grey : Colors.black , width: 1)),
|
||||
width: 50, height: 30,
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ Icon( Icons.delete, size: 18,
|
||||
color: widget.item.infos.isEmpty ? Colors.grey : Colors.black ) ]),
|
||||
)
|
||||
),
|
||||
]),
|
||||
...inf
|
||||
] ) ));
|
||||
}
|
||||
}
|
||||
174
lib/widgets/forms/sub_add_forms.dart
Normal file
174
lib/widgets/forms/sub_add_forms.dart
Normal file
@@ -0,0 +1,174 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/widgets/forms/sub_keys_forms.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class SubAddFormsWidget extends StatefulWidget {
|
||||
bool readOnly;
|
||||
SubMapFormsType type;
|
||||
String elementID = "";
|
||||
AbstractItem item;
|
||||
Dashboard dash;
|
||||
bool empty = false;
|
||||
List<Param> forms = [];
|
||||
SubAddFormsWidget ({ super.key, required this.dash, this.readOnly = false,
|
||||
this.empty = false, required this.item, required this.elementID,
|
||||
required this.type });
|
||||
@override SubAddFormsWidgetState createState() => SubAddFormsWidgetState();
|
||||
}
|
||||
class SubAddFormsWidgetState extends State<SubAddFormsWidget> {
|
||||
Param? addedparam;
|
||||
@override Widget build(BuildContext context) {
|
||||
AbstractInstance instance = widget.item.getSelectedInstance()!;
|
||||
var f = (widget.type == SubMapFormsType.INPUT ? instance.inputs : (
|
||||
widget.type == SubMapFormsType.OUTPUT ? instance.outputs : instance.env)).where( (e) => !e.readOnly).toList();
|
||||
widget.forms = f;
|
||||
if (addedparam != null) {
|
||||
widget.forms.add(addedparam!);
|
||||
}
|
||||
List<Widget> children = [];
|
||||
for (var param in widget.forms) {
|
||||
children.add(Row( mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
SubTextInputWidget(subkey: "key", readOnly: widget.readOnly,
|
||||
initialValue: param.name, width: 81, empty: widget.empty,
|
||||
change: (value) {
|
||||
setState(() {
|
||||
param.name = value;
|
||||
param.attr = value;
|
||||
if (addedparam?.value != null && addedparam?.name != null) {
|
||||
addedparam = null;
|
||||
}
|
||||
var sel = widget.item.getSelectedInstance();
|
||||
if (sel != null) {
|
||||
if (widget.type == SubMapFormsType.INPUT) { sel.inputs = [
|
||||
...sel.inputs.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
} else if (widget.type == SubMapFormsType.OUTPUT) {
|
||||
sel.outputs = [
|
||||
...sel.outputs.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
} else {
|
||||
sel.env = [
|
||||
...sel.env.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
}
|
||||
}
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
if (param.name == value) {
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}
|
||||
});
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
setState(() {});
|
||||
});
|
||||
}),
|
||||
const Padding(padding: EdgeInsets.only(left: 5, right: 5, top: 15), child: Text("=", textAlign: TextAlign.center,)),
|
||||
SubTextInputWidget(subkey: "value", initialValue: param.value, width: 81, empty: widget.empty,
|
||||
readOnly: widget.readOnly, change: (value) {
|
||||
param.value = value;
|
||||
if (addedparam?.value != null && addedparam?.name != null) {
|
||||
addedparam = null;
|
||||
}
|
||||
var sel = widget.item.getSelectedInstance();
|
||||
if (sel != null) {
|
||||
if (widget.type == SubMapFormsType.INPUT) { sel.inputs = [
|
||||
...sel.inputs.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
} else if (widget.type == SubMapFormsType.OUTPUT) {
|
||||
sel.outputs = [
|
||||
...sel.outputs.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
} else {
|
||||
sel.env = [
|
||||
...sel.env.where( (e) => e.readOnly ),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
}
|
||||
}
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
setState(() {});
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
if (param.value == value) {
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}
|
||||
});
|
||||
}),
|
||||
]));
|
||||
}
|
||||
return Column( crossAxisAlignment: CrossAxisAlignment.center, children : [
|
||||
widget.readOnly ? Container() : Row( mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
InkWell( onTap: () {
|
||||
if (widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null
|
||||
|| widget.forms[widget.forms.length - 1].value == null)) { return;}
|
||||
widget.forms.add(Param(readOnly: false));
|
||||
addedparam = widget.forms.last;
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
setState(() {});
|
||||
}, child: Container( margin: const EdgeInsets.only(top: 10),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null
|
||||
|| widget.forms[widget.forms.length - 1].value == null) ? Colors.grey : Colors.grey, width: 1)),
|
||||
width: 125, height: 30,
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add, color: widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null
|
||||
|| widget.forms[widget.forms.length - 1].value == null) ? Colors.grey : Colors.black,)),
|
||||
Text(widget.type == SubMapFormsType.ENV ? "env" : (widget.type == SubMapFormsType.INPUT ? "input" : "output"),
|
||||
style: TextStyle( color: widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null
|
||||
|| widget.forms[widget.forms.length - 1].value == null) ? Colors.grey : Colors.black))]),
|
||||
),
|
||||
),
|
||||
InkWell( onTap: () {
|
||||
if (addedparam != null) {
|
||||
addedparam = null;
|
||||
return setState(() {});
|
||||
}
|
||||
if (widget.forms.isEmpty) { return; }
|
||||
widget.forms.sublist(0, widget.forms.length - 1);
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
var sel = widget.item.getSelectedInstance();
|
||||
if (sel != null) {
|
||||
widget.forms.removeLast();
|
||||
if (widget.type == SubMapFormsType.INPUT) { sel.inputs = [
|
||||
...sel.inputs.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
} else if (widget.type == SubMapFormsType.OUTPUT) {
|
||||
sel.outputs = [
|
||||
...sel.outputs.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
} else {
|
||||
sel.env = [
|
||||
...sel.env.where( (e) => e.readOnly),
|
||||
...widget.forms.where((e) => e.name != null && e.value != null)
|
||||
];
|
||||
}
|
||||
}
|
||||
el!.element = widget.item as dynamic;
|
||||
setState(() { widget.dash.saveDash(widget.dash.id, context); });
|
||||
}, child:
|
||||
Container( margin: const EdgeInsets.only(left: 5, top: 10),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: widget.forms.isEmpty ? Colors.grey : Colors.black , width: 1)),
|
||||
width: 50, height: 30,
|
||||
child: Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ Icon( Icons.delete, size: 18,
|
||||
color: widget.forms.isEmpty ? Colors.grey : Colors.black ) ]),
|
||||
)
|
||||
),
|
||||
]),
|
||||
...children
|
||||
]);
|
||||
}
|
||||
}
|
||||
69
lib/widgets/forms/sub_expose_forms.dart
Normal file
69
lib/widgets/forms/sub_expose_forms.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/resources/processing.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class SubExposeFormsWidget extends StatefulWidget {
|
||||
bool readOnly;
|
||||
Expose item;
|
||||
Dashboard dash;
|
||||
String elementID = "";
|
||||
double width = 180;
|
||||
bool empty = false;
|
||||
SubExposeFormsWidget ({ super.key, required this.dash, this.readOnly = false,
|
||||
this.empty = false, required this.item, required this.elementID, required this.width });
|
||||
@override SubExposeFormsWidgetState createState() => SubExposeFormsWidgetState();
|
||||
}
|
||||
class SubExposeFormsWidgetState extends State<SubExposeFormsWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
return Column( children : [
|
||||
Container( margin: const EdgeInsets.only(left: 10, right: 10, top: 5),
|
||||
decoration: BoxDecoration(border: Border.all(color: Colors.grey, width: 1)),
|
||||
width: 180
|
||||
),
|
||||
SubTextInputWidget(subkey: "reference port", readOnly: widget.readOnly,
|
||||
initialValue: widget.item.port != null ? '${widget.item.port}' : null,
|
||||
width: widget.width, empty: widget.empty, change: (value) {
|
||||
try {
|
||||
widget.item.port = int.parse(value);
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
if (widget.item.port == int.parse(value) && int.parse(value) != 0) {
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}
|
||||
});
|
||||
} catch (e) { widget.item.port = null; }
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
}),
|
||||
SubTextInputWidget(
|
||||
readOnly: widget.readOnly,
|
||||
subkey: "PAT", initialValue: widget.item.PAT != null ? '${widget.item.PAT}' : null,
|
||||
width: widget.width, empty: widget.empty, change: (value) {
|
||||
try {
|
||||
widget.item.PAT = int.parse(value);
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
if (widget.item.PAT == int.parse(value) && int.parse(value) != 0) {
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}
|
||||
});
|
||||
} catch (e) { widget.item.PAT = null; }
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
}),
|
||||
SubTextInputWidget(subkey: "reverse path", initialValue: widget.item.PAT != null ? '${widget.item.PAT}' : null,
|
||||
readOnly: widget.readOnly,
|
||||
width: widget.width, empty: widget.empty, change: (value) {
|
||||
try {
|
||||
widget.item.path = value;
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
if (widget.item.path == value) { widget.dash.saveDash(widget.dash.id, context); }
|
||||
});
|
||||
} catch (e) { widget.item.path = null; }
|
||||
var el = widget.dash.getElement(widget.elementID);
|
||||
el!.element = widget.item as dynamic;
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
97
lib/widgets/forms/sub_keys_forms.dart
Normal file
97
lib/widgets/forms/sub_keys_forms.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_advanced_switch/flutter_advanced_switch.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/widgets/forms/sub_add_forms.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
|
||||
enum SubMapFormsType {
|
||||
ENV,
|
||||
INPUT,
|
||||
OUTPUT
|
||||
}
|
||||
// ignore: must_be_immutable
|
||||
class SubKeysMapFormsWidget extends StatefulWidget {
|
||||
bool readOnly = false;
|
||||
AbstractItem item;
|
||||
Dashboard dash;
|
||||
bool empty = false;
|
||||
SubMapFormsType type;
|
||||
String elementID = "";
|
||||
SubKeysMapFormsWidget({ super.key, required this.dash, required this.type, this.readOnly = false,
|
||||
this.empty = false, required this.item, required this.elementID });
|
||||
@override SubKeysMapFormsWidgetState createState() => SubKeysMapFormsWidgetState();
|
||||
}
|
||||
class SubKeysMapFormsWidgetState extends State<SubKeysMapFormsWidget> {
|
||||
bool _save = false;
|
||||
|
||||
List<Param> getParams(String fromID, String toID) {
|
||||
List<Param> arr = [];
|
||||
var els = widget.dash.elements.where( (e) => fromID.contains(e.id) || toID.contains(e.id));
|
||||
for (var element in els) {
|
||||
var g = GraphItem();
|
||||
g.fromDashboard(element.serialize());
|
||||
var e = g.getElement();
|
||||
if (e != null && e.getSelectedInstance() != null) {
|
||||
arr = [...arr, ...e.getSelectedInstance()!.env];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
List<Widget> getInstanceInOutput(AbstractItem? item, SubMapFormsType type) {
|
||||
List<Widget> children = [];
|
||||
if (item == null || item.getSelectedInstance() == null) {
|
||||
return [];
|
||||
}
|
||||
AbstractInstance instance = item.getSelectedInstance()!;
|
||||
List<Param> params = widget.type == SubMapFormsType.INPUT ? instance.inputs : ( widget.type == SubMapFormsType.OUTPUT ? instance.outputs : instance.env);
|
||||
for ( var param in params) {
|
||||
if (!param.readOnly) { continue; }
|
||||
dynamic env;
|
||||
if (param.value == null && param.attr != null) {
|
||||
var s = item.serialize();
|
||||
s.addAll(item.getSelectedInstance()?.serialize() ?? {});
|
||||
env = s[param.attr!];
|
||||
} else { env = param.value; }
|
||||
_save = true;
|
||||
if (env is bool) {
|
||||
var ctrl = ValueNotifier<bool>(env);
|
||||
children.add(AdvancedSwitch(
|
||||
width: 150.0,
|
||||
height: 25.0,
|
||||
controller: ctrl,
|
||||
enabled: false,
|
||||
activeChild: Text(param.name!, style: const TextStyle(color: Colors.white)),
|
||||
inactiveChild: Text("no ${param.name!}", style: const TextStyle(color: Colors.white)),
|
||||
activeColor: Colors.green,
|
||||
inactiveColor: redColor,
|
||||
onChanged: (value) {},
|
||||
));
|
||||
} else {
|
||||
children.add(SubTextInputWidget( subkey: param.name!, width: 180, empty: false, change: (value) { },
|
||||
initialValue: env, readOnly: true, noLabel: false, copyLabel: true ));
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
List<Widget> children = [];
|
||||
var newwidget = getInstanceInOutput(widget.item, widget.type);
|
||||
children.add(Column( children : [
|
||||
Padding( padding: const EdgeInsets.only(top: 10),
|
||||
child: Text("<${widget.type == SubMapFormsType.INPUT ? "INPUT" : (widget.type == SubMapFormsType.OUTPUT ? "OUTPUT" : "")} ENV VARIABLES>",
|
||||
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center)),
|
||||
...newwidget,
|
||||
SubAddFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID, type: widget.type),
|
||||
Container(width: 200, padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1)))),
|
||||
]));
|
||||
if (_save) {
|
||||
widget.dash.saveDash(widget.dash.id, context);
|
||||
}
|
||||
return Column( children : children );
|
||||
}
|
||||
}
|
||||
130
lib/widgets/inputs/shallow_dropdown_input.dart
Normal file
130
lib/widgets/inputs/shallow_dropdown_input.dart
Normal file
@@ -0,0 +1,130 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
|
||||
class ShallowDropdownInputWidget extends StatefulWidget {
|
||||
double? width;
|
||||
double? height;
|
||||
CollaborativeAreaType type = CollaborativeAreaType.workspace;
|
||||
Future<List<Shallow>> Function()? all;
|
||||
Future<void> Function(String)? load;
|
||||
Future<void> Function(String)? remove;
|
||||
bool Function(String?)? canLoad;
|
||||
bool Function(String?)? canRemove;
|
||||
void Function(String?)? change;
|
||||
DropdownMenuItem Function(Shallow)? maptoDropdown;
|
||||
String? current;
|
||||
Widget? prefixIcon;
|
||||
IconData? iconLoad;
|
||||
IconData? iconRemove;
|
||||
String? label;
|
||||
String? hint;
|
||||
|
||||
String? tooltipLoad;
|
||||
String? tooltipRemove;
|
||||
|
||||
Color? filled;
|
||||
Color? hintColor;
|
||||
Color? color;
|
||||
|
||||
bool deletion = false;
|
||||
|
||||
ShallowDropdownInputWidget ({ Key? key, this.width, this.current, required this.all, this.prefixIcon,
|
||||
this.iconLoad, this.iconRemove, this.hint, this.filled, this.hintColor, this.color, this.height,
|
||||
this.tooltipLoad, this.tooltipRemove, this.deletion = false, this.maptoDropdown, this.label,
|
||||
required this.type, this.canLoad, this.canRemove, this.load, this.remove, this.change }): super(key: key);
|
||||
@override ShallowDropdownInputWidgetState createState() => ShallowDropdownInputWidgetState();
|
||||
}
|
||||
class ShallowDropdownInputWidgetState extends State<ShallowDropdownInputWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
if (widget.deletion && widget.remove == null) {
|
||||
widget.remove =(p0) async => widget.current = null;
|
||||
}
|
||||
var t = widget.type == CollaborativeAreaType.workspace ? "workspace" : (widget.type == CollaborativeAreaType.workflow ? "workflow" : "peer");
|
||||
return FutureBuilder(future: widget.all!(), builder: (b, s) {
|
||||
List<DropdownMenuItem> items = [];
|
||||
if (widget.maptoDropdown != null) {
|
||||
items = s.data?.map((e) => widget.maptoDropdown!(e)).toList() ?? <DropdownMenuItem>[];
|
||||
} else {
|
||||
items = s.data?.map((e) => DropdownMenuItem(value: e.id,child: Text(e.name),)).toList() ?? <DropdownMenuItem>[];
|
||||
}
|
||||
return Row( children: [
|
||||
Tooltip( message: widget.hint ?? "current $t", child:
|
||||
Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
canvasColor: widget.filled ??Colors.white,
|
||||
),
|
||||
child: Container( height: widget.height ?? 50,
|
||||
width: (widget.width ?? getMainWidth(context)) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Center(child: DropdownButtonFormField(
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
widget.current = value;
|
||||
if (widget.change != null) {
|
||||
widget.change!(value);
|
||||
}
|
||||
});
|
||||
},
|
||||
value: widget.current != null && !items.map( ((e) => e.value)).contains(widget.current) ? null : widget.current,
|
||||
isExpanded: true,
|
||||
style: TextStyle(color: widget.color ?? Colors.black, fontSize: 15),
|
||||
hint: Text(widget.hint ?? "load $t...",
|
||||
style: TextStyle(color: widget.hintColor ??midColor, fontSize: 14)),
|
||||
icon: Icon( // Add this
|
||||
Icons.arrow_drop_down, // Add this
|
||||
color: widget.hintColor ?? Colors.grey , // Add thisprefixIcon
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
label: widget.label == null ? null : Text(widget.label!),
|
||||
alignLabelWithHint: false,
|
||||
prefixIconColor: Colors.grey,
|
||||
prefixIcon: widget.prefixIcon,
|
||||
suffixIconColor: widget.hintColor ?? Colors.grey ,
|
||||
focusedBorder: InputBorder.none,
|
||||
fillColor: widget.filled ??Colors.white,
|
||||
enabledBorder: InputBorder.none,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.only(left: (widget.width ?? 400) < 200 ? 0 : 30, right: (widget.width ?? 400) < 200 ? 0 : 30, top: 18, bottom: 18),
|
||||
),
|
||||
items: items,
|
||||
))))),
|
||||
widget.load == null ? Container() : Tooltip(
|
||||
message: widget.tooltipLoad ?? "load $t",
|
||||
child:InkWell(
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () async {
|
||||
if (widget.canLoad == null || !widget.canLoad!(widget.current)
|
||||
|| widget.load == null || widget.current == null) {
|
||||
return;
|
||||
}
|
||||
await widget.load!(widget.current!);
|
||||
setState(() { });
|
||||
},
|
||||
child: Container( width: 50,height: 50,
|
||||
color: Colors.black,
|
||||
child: Icon( widget.iconLoad ?? Icons.add, color: widget.current == null || widget.canLoad == null || !widget.canLoad!(widget.current) ? Colors.grey : Colors.white)
|
||||
)
|
||||
)
|
||||
),
|
||||
widget.remove == null ? Container() : Tooltip(
|
||||
message: widget.tooltipRemove ?? "remove $t",
|
||||
child: InkWell( mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () async {
|
||||
if (widget.canRemove == null || !widget.canRemove!(widget.current) || widget.remove == null || widget.current == null) {
|
||||
return;
|
||||
}
|
||||
await widget.remove!(widget.current!);
|
||||
setState(() { });
|
||||
},
|
||||
child: Container( width: 50,height: 50,
|
||||
decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: midColor))),
|
||||
child: Icon(widget.iconRemove ?? Icons.delete, color: widget.current == null || widget.canRemove == null || !widget.canRemove!(widget.current) ? Colors.grey : Colors.white)) )
|
||||
),
|
||||
]); });
|
||||
}
|
||||
}
|
||||
142
lib/widgets/inputs/shallow_text_input.dart
Normal file
142
lib/widgets/inputs/shallow_text_input.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
|
||||
class ShallowTextInputWidget extends StatefulWidget {
|
||||
double? width;
|
||||
CollaborativeAreaType type = CollaborativeAreaType.workspace;
|
||||
Future<void> Function(Map<String,dynamic>)? load;
|
||||
Future<void> Function(String)? loadStr;
|
||||
Future<void> Function(String)? remove;
|
||||
bool Function(String?)? canLoad;
|
||||
bool Function(String?)? canRemove;
|
||||
void Function(String?)? change;
|
||||
String? current;
|
||||
String? compare;
|
||||
bool readOnly;
|
||||
IconData? iconLoad;
|
||||
IconData? iconRemove;
|
||||
|
||||
MainAxisAlignment alignment = MainAxisAlignment.start;
|
||||
|
||||
String? hint;
|
||||
|
||||
String? tooltipLoad;
|
||||
String? tooltipRemove;
|
||||
|
||||
Color? filled;
|
||||
Color? hintColor;
|
||||
Color? color;
|
||||
List<ShallowTextInputWidget> forms = [];
|
||||
|
||||
String? attr;
|
||||
|
||||
ShallowTextInputWidget ({ Key? key, this.width, this.current, this.attr, this.readOnly = false, this.alignment = MainAxisAlignment.start,
|
||||
this.iconLoad, this.iconRemove, this.hint, this.forms = const [], this.loadStr,
|
||||
this.tooltipLoad = "", this.tooltipRemove = "",
|
||||
this.filled, this.hintColor, this.color,
|
||||
required this.type, this.canLoad, this.canRemove, this.load, this.remove, this.change }): super(key: key);
|
||||
@override ShallowTextInputWidgetState createState() => ShallowTextInputWidgetState();
|
||||
|
||||
Map<String, dynamic> serialize() {
|
||||
Map<String, dynamic> map = { "name" : current };
|
||||
for (var form in forms) {
|
||||
if (form.attr == null) {
|
||||
continue;
|
||||
}
|
||||
map[form.attr!] = form.current;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
bool validate() {
|
||||
return canLoad == null ? true : canLoad!(current);
|
||||
}
|
||||
}
|
||||
class ShallowTextInputWidgetState extends State<ShallowTextInputWidget> {
|
||||
TextEditingController ctrl = TextEditingController();
|
||||
|
||||
bool validForms() {
|
||||
for (var form in widget.forms) {
|
||||
if (!form.validate()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
var t = widget.type == CollaborativeAreaType.workspace ? "workspace" : (widget.type == CollaborativeAreaType.workflow ? "workflow" : "peer");
|
||||
ctrl.text = widget.current ?? "";
|
||||
return Row( mainAxisAlignment: widget.alignment, children: [
|
||||
Tooltip( message: widget.hint ?? "current $t", child:
|
||||
Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
canvasColor: midColor,
|
||||
),
|
||||
child: Container( height: 50, width: (widget.width ?? getMainWidth(context)) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50),
|
||||
decoration: const BoxDecoration( color: Colors.white ),
|
||||
child: TextFormField(
|
||||
enabled: !widget.readOnly,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
widget.current = value;
|
||||
if (widget.change != null) {
|
||||
widget.change!(value);
|
||||
}
|
||||
});
|
||||
},
|
||||
controller: ctrl,
|
||||
style: TextStyle(color: widget.color ?? Colors.black, fontSize: 15),
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
fillColor: widget.filled ?? Colors.white,
|
||||
hintText: widget.hint ?? "enter $t ${widget.attr ?? "name"}...",
|
||||
contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 18, bottom: 18),
|
||||
hintStyle: TextStyle(color: widget.hintColor ??const Color.fromARGB(255, 85, 44, 44), fontSize: 14)),
|
||||
),
|
||||
))),
|
||||
widget.load == null && widget.loadStr == null ? Container() : Tooltip(
|
||||
message: widget.tooltipLoad ?? "add $t",
|
||||
child:InkWell(
|
||||
mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () async {
|
||||
if (widget.canLoad == null || !widget.canLoad!(widget.current) || !validForms()
|
||||
|| (widget.load == null && widget.loadStr == null) || widget.current == null) {
|
||||
return;
|
||||
}
|
||||
if (widget.loadStr != null) {
|
||||
await widget.loadStr!(widget.current!);
|
||||
} else {
|
||||
await widget.load!(widget.serialize());
|
||||
}
|
||||
setState(() { });
|
||||
},
|
||||
child: Container( width: 50,height: 50,
|
||||
color: Colors.black,
|
||||
child: Icon( widget.iconLoad ?? Icons.add, color: widget.current == null || !validForms()
|
||||
|| widget.canLoad == null || !widget.canLoad!(widget.current) ? Colors.grey : Colors.white)
|
||||
)
|
||||
)
|
||||
),
|
||||
widget.remove == null ? Container() : Tooltip(
|
||||
message: widget.tooltipRemove ?? "refresh entry",
|
||||
child: InkWell( mouseCursor: SystemMouseCursors.click,
|
||||
onTap: () async {
|
||||
if (widget.canRemove == null || !widget.canRemove!(widget.current) || widget.remove == null || widget.current == null) {
|
||||
return;
|
||||
}
|
||||
await widget.remove!(widget.current!);
|
||||
setState(() { });
|
||||
},
|
||||
child: Container( width: 50,height: 50,
|
||||
decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: midColor))),
|
||||
child: Icon(widget.iconRemove ?? Icons.delete, color: widget.current == null || widget.canRemove == null || !widget.canRemove!(widget.current) ? Colors.grey : Colors.white)) )
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
43
lib/widgets/inputs/sub_dropdown_input .dart
Normal file
43
lib/widgets/inputs/sub_dropdown_input .dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SubDropdownInputWidget extends StatefulWidget {
|
||||
String subkey;
|
||||
double width;
|
||||
bool empty;
|
||||
String? initialValue;
|
||||
List<DropdownMenuItem<String>> dropdownMenuEntries = [];
|
||||
void Function(String?)? change = (value) {};
|
||||
SubDropdownInputWidget ({ super.key, required this.dropdownMenuEntries, this.initialValue,
|
||||
required this.subkey, required this.width, required this.empty, required this.change });
|
||||
@override SubDropdownInputWidgetState createState() => SubDropdownInputWidgetState();
|
||||
}
|
||||
class SubDropdownInputWidgetState extends State<SubDropdownInputWidget> {
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Tooltip( message: widget.subkey,
|
||||
child: Container( margin: EdgeInsets.only(top: widget.empty ? 0 : 15),
|
||||
width: widget.width, height: 30,
|
||||
child: DropdownButtonFormField(
|
||||
isExpanded: true,
|
||||
items: widget.dropdownMenuEntries,
|
||||
value: widget.initialValue,
|
||||
onChanged: widget.change,
|
||||
style: const TextStyle(fontSize: 12,color: Colors.black, overflow: TextOverflow.ellipsis),
|
||||
decoration: InputDecoration(
|
||||
hintText: "select ${widget.subkey}...",
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
labelText: widget.subkey,
|
||||
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),
|
||||
),
|
||||
))),
|
||||
]);
|
||||
}
|
||||
}
|
||||
62
lib/widgets/inputs/sub_text_input.dart
Normal file
62
lib/widgets/inputs/sub_text_input.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'package:alert_banner/exports.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:oc_front/widgets/dialog/alert.dart';
|
||||
|
||||
class SubTextInputWidget extends StatefulWidget {
|
||||
String subkey;
|
||||
String? initialValue;
|
||||
double width;
|
||||
bool empty;
|
||||
bool noLabel;
|
||||
bool readOnly = false;
|
||||
bool copyLabel = false;
|
||||
void Function(String) change = (value) {};
|
||||
SubTextInputWidget ({ Key? key,
|
||||
required this.subkey, this.readOnly = false, this.noLabel = false, this.copyLabel = false,
|
||||
this.initialValue, required this.width, required this.empty, required this.change }):
|
||||
super(key: key);
|
||||
@override SubTextInputWidgetState createState() => SubTextInputWidgetState();
|
||||
}
|
||||
class SubTextInputWidgetState extends State<SubTextInputWidget> {
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
if (widget.readOnly && widget.initialValue == null) {
|
||||
return Container();
|
||||
}
|
||||
return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Tooltip( message: widget.subkey,
|
||||
child: Container( margin: EdgeInsets.only(top: widget.empty ? 0 : 15),
|
||||
width: widget.width - (widget.readOnly ? 40 : 0), height: 30,
|
||||
child: TextFormField( textAlign: TextAlign.start,
|
||||
enabled: !widget.readOnly,
|
||||
initialValue: widget.initialValue,
|
||||
onChanged: widget.change,
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
hintText: "enter ${widget.subkey}...",
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
labelText: widget.noLabel ? "" : widget.subkey,
|
||||
alignLabelWithHint: false,
|
||||
errorStyle: const TextStyle(fontSize: 0),
|
||||
hintStyle: const TextStyle(fontSize: 10),
|
||||
labelStyle: const TextStyle(fontSize: 12),
|
||||
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),
|
||||
),
|
||||
))),
|
||||
widget.readOnly ? InkWell( onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: widget.copyLabel ? "\$${widget.subkey}" : widget.initialValue!));
|
||||
showAlertBanner(context, () {}, const InfoAlertBannerChild(text: "successfully add to clipboard"), // <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
}, child: Container( margin: EdgeInsets.only(left: 5, top: widget.empty ? 0 : 15),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)),
|
||||
width: 35, height: 30,
|
||||
child: const Row( mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ Icon(Icons.copy, color: Colors.black, size: 15,) ]),
|
||||
)) : Container()
|
||||
]);
|
||||
}
|
||||
}
|
||||
24
lib/widgets/items/infos.dart
Normal file
24
lib/widgets/items/infos.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class InfosWidget extends StatefulWidget {
|
||||
AbstractItem item;
|
||||
InfosWidget ({ super.key, required this.item });
|
||||
@override InfosWidgetState createState() => InfosWidgetState();
|
||||
}
|
||||
class InfosWidgetState extends State<InfosWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
List<Widget> children = [];
|
||||
var obj = widget.item.infos();
|
||||
for (var key in obj.keys) {
|
||||
children.add(
|
||||
Padding(padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 100),
|
||||
child: Text("$key : ${obj[key] ?? "no $key"}",
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600))),
|
||||
);
|
||||
}
|
||||
return Wrap( children: children);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/widgets/items/items_details/data_item.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/pages/shared.dart';
|
||||
import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart';
|
||||
import 'package:oc_front/widgets/inputs/sub_dropdown_input%20.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ItemWidget extends StatefulWidget {
|
||||
AbstractItem item;
|
||||
ItemWidget ({ super.key, required this.item });
|
||||
@@ -10,28 +14,88 @@ class ItemWidget extends StatefulWidget {
|
||||
}
|
||||
class ItemWidgetState extends State<ItemWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
Widget w = Container();
|
||||
/* if (isData(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); }
|
||||
else if (isComputing(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); }
|
||||
else if (isDataCenter(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); }
|
||||
else if (isStorage(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } */
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height - 300,
|
||||
List<Widget> widgets = [
|
||||
Container( margin: EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: midColor))),
|
||||
width: getMainWidth(context) / 2,
|
||||
child: Center(child: Padding( padding: EdgeInsets.only(bottom: 20),
|
||||
child: Text("RESOURCE INFORMATIONS", style: TextStyle(fontSize: 18, color: Colors.grey, fontWeight: FontWeight.w500)))))
|
||||
];
|
||||
var infos = widget.item.infos();
|
||||
var count = 0;
|
||||
for (var info in infos.keys) {
|
||||
count++;
|
||||
widgets.add(Padding( padding: EdgeInsets.symmetric(vertical: 5), child : Row(children: [
|
||||
Padding( padding: EdgeInsets.only(left: 50, right: 10), child : Text("${info.toUpperCase().replaceAll("_", " ")} :", style: TextStyle(fontSize: 15, color: Colors.grey))),
|
||||
Text("${infos[info] is bool ? (infos[info] == true ? "yes" : "no") : infos[info] ?? "unknown"}",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500))
|
||||
])));
|
||||
}
|
||||
if (count == 0 ) {
|
||||
widgets.add(Center(child: Padding( padding: EdgeInsets.symmetric(vertical: 5), child : Row(children: [
|
||||
Padding( padding: EdgeInsets.only(left: 50, right: 10), child : Text("NO INFORMATION", style: TextStyle(fontSize: 15, color: Colors.grey))),
|
||||
]))));
|
||||
}
|
||||
List<Widget> widgetsInstance = [];
|
||||
List<Shallow> dpItems = [];
|
||||
for (var (i, instance) in widget.item.instances.indexed) {
|
||||
dpItems.add(Shallow(id: "$i", name: instance.name ?? ""));
|
||||
}
|
||||
if (dpItems.isNotEmpty) {
|
||||
widgetsInstance.add(Center( child: Padding(padding: EdgeInsets.only(bottom: 15), child:
|
||||
ShallowDropdownInputWidget( all: () async => dpItems, width: (getWidth(context) / 2) - 25,
|
||||
label: "instances", type: CollaborativeAreaType.resource, height: 65,
|
||||
current: "${widget.item.selectedInstance}", change: (value) {
|
||||
if (value != null) { setState(() { widget.item.selectedInstance = int.parse(value); }); }
|
||||
},
|
||||
))
|
||||
));
|
||||
}
|
||||
if (widget.item.instances.length > widget.item.selectedInstance) {
|
||||
var instance = widget.item.instances[widget.item.selectedInstance];
|
||||
widgetsInstance.add(Container(height: 20, width: getWidth(context) / 2,));
|
||||
var count = 0;
|
||||
for (var info in instance.infos().keys) {
|
||||
if (instance.infos()[info] == null || instance.infos()[info] is List || instance.infos()[info] is Map) { continue; }
|
||||
count++;
|
||||
widgetsInstance.add(Center(child: Padding( padding: EdgeInsets.symmetric(vertical: 5), child : Row(children: [
|
||||
Padding( padding: EdgeInsets.only(left: 50, right: 10), child : Text("${info.toUpperCase().replaceAll("_", " ")} :", style: TextStyle(fontSize: 15, color: Colors.grey))),
|
||||
Text("${instance.infos()[info] is bool ? (instance.infos()[info] == true ? "yes" : "no") : instance.infos()[info] ?? "unknown"}",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500))
|
||||
]))));
|
||||
}
|
||||
if (count == 0 ) {
|
||||
widgetsInstance.add(Padding( padding: EdgeInsets.symmetric(vertical: 5), child : Row(children: [
|
||||
Padding( padding: EdgeInsets.only(left: 50, right: 10), child : Text("NO INSTANCE INFORMATION", style: TextStyle(fontSize: 15, color: Colors.grey))),
|
||||
])));
|
||||
}
|
||||
}
|
||||
Widget w = Column( mainAxisSize: MainAxisSize.max, children: widgets );
|
||||
Widget w2 = Column( mainAxisSize: MainAxisSize.max, children: widgetsInstance );
|
||||
return SizedBox(
|
||||
height: getHeight(context) - 200,
|
||||
child: SingleChildScrollView(
|
||||
child: Column( children: [
|
||||
child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
widget.item.description == null ? Container() : Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
width: getMainWidth(context),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey.shade300))),
|
||||
padding: const EdgeInsets.all(30),
|
||||
child: Text(widget.item.description!,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(bottom: BorderSide(color: midColor))),
|
||||
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 50),
|
||||
child: Text(widget.item.description!.length > 350 ? "${widget.item.description!.substring(0, 347)}..." : widget.item.description!,
|
||||
style: TextStyle(fontSize: 15, color: Colors.grey, fontWeight: FontWeight.w500))),
|
||||
Container(padding: const EdgeInsets.all(30),
|
||||
color: Colors.grey.shade300,
|
||||
width: MediaQuery.of(context).size.width / 2,
|
||||
child: w
|
||||
)
|
||||
Row( children: [
|
||||
Container(padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
height: getHeight(context) - 300,
|
||||
decoration: BoxDecoration(border: Border(right: BorderSide(color: midColor))),
|
||||
alignment: Alignment.topLeft, width: getMainWidth(context) / 2, child: w),
|
||||
Container(height: getHeight(context) - 300,
|
||||
alignment: Alignment.topRight, width: getMainWidth(context) / 2, child: w2)
|
||||
])
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'package:oc_front/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/core/services/router.dart';
|
||||
import 'package:oc_front/models/resources/resources.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
|
||||
const List<GlobalKey<State>> _empty = [];
|
||||
// ignore: must_be_immutable
|
||||
@@ -18,26 +18,28 @@ class ItemRowWidget extends StatefulWidget {
|
||||
}
|
||||
class ItemRowWidgetState extends State<ItemRowWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
double imageSize = MediaQuery.of(context).size.width != widget.contextWidth ? 0 : 80;
|
||||
var ratio = MediaQuery.of(context).size.width != widget.contextWidth ? 0.5 : 1; // 2;
|
||||
double imageSize = widget.contextWidth <= 400 ? 0 : 80;
|
||||
var ratio = getMainWidth(context) != widget.contextWidth ? 0.5 : 1; // 2;
|
||||
var itemWidth = (((widget.contextWidth - imageSize) / 3) - 80) / ratio;
|
||||
itemWidth = itemWidth > 100 ? 100 : ( itemWidth < 40 ? 40 : itemWidth );
|
||||
var endWidth = (itemWidth * ratio) + 80;
|
||||
Image? image;
|
||||
if (widget.item.logo != null) {
|
||||
image = Image.memory(base64Decode(widget.item.logo ?? ""), width: imageSize, height: imageSize);
|
||||
image = Image.network(widget.item.logo ?? "", width: imageSize, height: imageSize);
|
||||
}
|
||||
Widget w = Container(
|
||||
width: widget.contextWidth,
|
||||
height: 100,
|
||||
decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey.shade300)) ),
|
||||
padding: EdgeInsets.only(left: imageSize == 0 ? 20 : 0),
|
||||
decoration: BoxDecoration( border: Border(bottom: BorderSide(color: midColor)) ),
|
||||
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),) : Container( padding: const EdgeInsets.all(10),
|
||||
constraints: BoxConstraints(maxWidth: imageSize, minWidth: imageSize),
|
||||
child: image ?? Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp',
|
||||
height: imageSize, width: imageSize)),
|
||||
Container(
|
||||
SizedBox(
|
||||
width: widget.low ? widget.contextWidth - 20 : widget.contextWidth - (imageSize + 20) - endWidth,
|
||||
child: Padding(padding: widget.contextWidth != MediaQuery.of(context).size.width ?
|
||||
child: Padding(padding: widget.contextWidth != getMainWidth(context) ?
|
||||
const EdgeInsets.symmetric(horizontal: 10) : const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
@@ -45,26 +47,23 @@ class ItemRowWidgetState extends State<ItemRowWidget> {
|
||||
widget.low ? Container() : Container(padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
||||
margin: const EdgeInsets.only(right: 20),
|
||||
decoration: BoxDecoration(
|
||||
color: isData(widget.item.topic) ? Colors.blue :
|
||||
isComputing(widget.item.topic) ? Colors.green :
|
||||
isDataCenter(widget.item.topic) ? Colors.orange :
|
||||
isStorage(widget.item.topic) ? Colors.red : Colors.grey,
|
||||
color: getColor(widget.item.topic),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text( MediaQuery.of(context).size.width < 600 ? "" : widget.item.type.toString(),
|
||||
child: Text( getMainWidth(context) < 600 ? "" : widget.item.topic.toString(),
|
||||
style: const TextStyle(fontSize: 10, color: Colors.white, fontWeight: FontWeight.w600)),
|
||||
),
|
||||
Expanded( child: Text(widget.item.name?.toUpperCase() ?? "",
|
||||
style: TextStyle(fontSize: widget.low ? 14 : 20, overflow: TextOverflow.ellipsis, fontWeight: FontWeight.w600, color: Color(0xFFF67C0B9))),
|
||||
)
|
||||
]),
|
||||
Text( "From ${widget.item.owner ?? "unknown owner"}",
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey, overflow: TextOverflow.ellipsis)),
|
||||
widget.item.owners.isEmpty ? Container() : Text( "From ${widget.item.owners.map( (e) => e.name).join(", ")}",
|
||||
style: const TextStyle(fontSize: 14, color: Colors.grey, overflow: TextOverflow.ellipsis)),
|
||||
Text(widget.item.shortDescription ?? "", style: const TextStyle(fontSize: 12, overflow: TextOverflow.ellipsis)),
|
||||
],)
|
||||
)
|
||||
),
|
||||
widget.low ? Container() : Container(
|
||||
widget.low ? Container() : SizedBox(
|
||||
width: endWidth,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -83,12 +82,13 @@ class ItemRowWidgetState extends State<ItemRowWidget> {
|
||||
constraints: const BoxConstraints(maxWidth: 80),
|
||||
width: itemWidth,
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [BoxShadow(color: Colors.grey.shade300, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))],
|
||||
color: (WorkspaceLocal.hasItem(widget.item) ? Colors.red : const Color.fromRGBO(38, 166, 154, 1)),
|
||||
boxShadow: [BoxShadow(color: midColor, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))],
|
||||
color: (WorkspaceLocal.hasItem(widget.item) ? redColor : lightColor ),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Icon(WorkspaceLocal.hasItem(widget.item) ? Icons.remove_shopping_cart : Icons.add_shopping_cart,
|
||||
color: Colors.white, size: 20 ))
|
||||
color: Colors.white, size: 20 )
|
||||
)
|
||||
),
|
||||
...(ratio > 1 ? [Padding( padding: const EdgeInsets.only(left: 20),
|
||||
child: InkWell(
|
||||
@@ -99,8 +99,8 @@ class ItemRowWidgetState extends State<ItemRowWidget> {
|
||||
constraints: const BoxConstraints(maxWidth: 80, minWidth: 40),
|
||||
width: itemWidth,
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [BoxShadow(color: Colors.grey.shade300, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))],
|
||||
color: Colors.grey.shade300,
|
||||
boxShadow: [BoxShadow(color: midColor, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))],
|
||||
color: midColor,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const Icon(Icons.favorite_border, color: Colors.white, size: 20 ))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user