intermediate

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

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

View File

@ -8,8 +8,10 @@
import 'dart:io'; // flutter_ignore: dart_io_import.
import '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();

View File

@ -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"
}

View File

@ -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/

View File

@ -14,3 +14,6 @@ shared_preferences_linux=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_l
shared_preferences_web=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/
shared_preferences_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/
webview_flutter=/home/mr/.pub-cache/hosted/pub.dev/webview_flutter-4.8.0/
webview_flutter_android=/home/mr/.pub-cache/hosted/pub.dev/webview_flutter_android-3.16.3/
webview_flutter_wkwebview=/home/mr/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-3.14.0/

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,65 +1,123 @@
# ninja log v5
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

View File

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

View File

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

View File

@ -14,6 +14,7 @@
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/NOTICES.Z
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/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

View File

@ -1,29 +0,0 @@
import 'package:oc_front/models/search.dart';
class Graphs {
static const Map<String, Graph> graphs = {};
static Graph getGraph(String id) {
return graphs[id]!;
}
static void addGraph(String id, Graph graph) {
graphs[id] = graph;
}
static void removeGraph(String id) {
graphs.remove(id);
}
static void clear() {
graphs.clear();
}
}
class Graph {
String id;
List<AbstractItem> items = [];
Graph({ required this.id, required this.items }) {
}
}

View File

@ -1,84 +1,177 @@
import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:oc_front/core/sections/end_drawer.dart';
import 'package:oc_front/models/search.dart';
import 'package:oc_front/models/workspace.dart';
import 'package:oc_front/core/services/specialized_services/item_service.dart';
import 'package:oc_front/core/services/specialized_services/workspace_service.dart';
import 'package:oc_front/pages/catalog.dart';
import 'package:oc_front/pages/catalog_item.dart';
import 'package:oc_front/pages/workflow.dart';
class WorkSpaceItem {
String? id;
String? name;
WorkSpaceItem({this.id, this.name});
}
class WorkspaceLocal {
static Workspace? workspace;
static String? current;
static Map<String, Workspace> workspaces = {};
static final WorkspaceService _service = WorkspaceService();
static List<AbstractItem> items = [];
static void init(BuildContext context) {
static void init(BuildContext context, bool changeCurrent) {
_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!); } }
);
if (value.data != null && value.data!.values.isNotEmpty ) {
var vals = value.data!.values;
for (var element in vals) {
var ws = Workspace().deserialize(element);
if (ws.id == null) { continue; }
workspaces[ws.id!] = ws;
if (current == null) {
current ??= ws.id;
workspaces[current!] = ws;
_service.put(context, ws.id!, { "active" : true }, {});
}
}
if (workspace!.computing.isNotEmpty) {
ItemService<ComputingItem, ComputingItem> computingService = ItemService<ComputingItem, ComputingItem>();
for (var element in workspace!.computing) {
if (WorkspaceLocal.hasItemByID(element)) { continue; }
computingService.get(context, element).then(
(value) { if (value.data != null) { items.add(value.data!); } }
);
}
}
if (workspace!.datacenter.isNotEmpty) {
ItemService<DataCenterItem, DataCenterItem> dataCenterService = ItemService<DataCenterItem, DataCenterItem>();
for (var element in workspace!.datacenter) {
if (WorkspaceLocal.hasItemByID(element)) { continue; }
dataCenterService.get(context, element).then(
(value) { if (value.data != null) { items.add(value.data!); } }
);
}
}
if (workspace!.storage.isNotEmpty) {
ItemService<StorageItem, StorageItem> storageService = ItemService<StorageItem, StorageItem>();
for (var element in workspace!.storage) {
if (WorkspaceLocal.hasItemByID(element)) { continue; }
storageService.get(context, element).then(
(value) { if (value.data != null) { items.add(value.data!); } }
);
if (ws.active == true && changeCurrent) {
current = ws.id;
}
fill();
}
} else {
WorkspaceLocal.createWorkspace("main", context);
}
});
}
static List<AbstractItem> byTopic(String topic) {
static void fill() {
items = [];
if (workspaces[current] != null) {
for (var element in workspaces[current]!.datas) {
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
items.add(element);
}
for (var element in workspaces[current]!.processings) {
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
items.add(element); }
for (var element in workspaces[current]!.datacenters) {
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
items.add(element);
}
for (var element in workspaces[current]!.storages) {
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
items.add(element);
}
for (var element in workspaces[current]!.workflows) {
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
items.add(element);
}
}
}
static Workspace? getCurrentWorkspace() {
return workspaces[current];
}
static Future<void> deleteWorkspace(String id) async {
if (workspaces.containsKey(id) && workspaces.length == 1) { return; }
workspaces.remove(id);
await _service.delete(null, id, {});
current = workspaces.keys.first;
}
static Future<void> createWorkspace(String name, BuildContext? context) async {
Workspace n = Workspace(name: name);
await _service.post(context, n.serialize(), {}).then((value) {
if (value.data != null) {
workspaces[value.data!.id!] = value.data!;
current = value.data!.id;
fill();
endDrawerKey.currentState?.setState(() {});
CatalogFactory.key.currentState?.setState(() {});
CatalogItemFactory.key.currentState?.setState(() {});
WorkflowFactory.key.currentState?.setState(() {});
}
});
}
static void changeWorkspace(String id) {
current = id;
fill();
endDrawerKey.currentState?.setState(() {});
CatalogFactory.key.currentState?.setState(() {});
CatalogItemFactory.key.currentState?.setState(() {});
WorkflowFactory.key.currentState?.setState(() {});
}
static List<WorkSpaceItem> getWorkspacesIDS() {
List<WorkSpaceItem> res = [];
for (var element in workspaces.entries) {
res.add(WorkSpaceItem(id: element.key, name: element.value.name));
}
return res;
}
static List<AbstractItem> byTopic(String topic, bool all) {
if (all) {
List<AbstractItem<FlowData>> d = [];
for (var w in workspaces.values) {
d = [ ...d, ...w.datas.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.datacenters.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.processings.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.storages.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.workflows.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
}
return d.where((element) => element.topic.toString() == topic).toList();
}
return WorkspaceLocal.items.where((element) => element.topic.toString() == topic).toList();
}
static AbstractItem? getItem(String id) {
static AbstractItem? getItem(String id, bool all) {
if (all) {
List<AbstractItem<FlowData>> d = [];
for (var w in workspaces.values) {
d = [ ...d, ...w.datas.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.datacenters.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.processings.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.storages.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
d = [ ...d, ...w.workflows.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
}
return d.isEmpty ? null : d.first;
}
var found = WorkspaceLocal.items.where((element) => element.id.toString() == id);
return found.isEmpty ? null : found.first;
}
static void addItem(AbstractItem item) {
if (!WorkspaceLocal.hasItem(item)) {
if (!WorkspaceLocal.hasItem(item) && workspaces[current] != null && workspaces[current]!.id != null) {
items.add(item);
try {
_service.post(null, {}, { "id" : item.id.toString(), "rtype" : item.type.toString() });
if (item.topic == "data") { workspaces[current]!.datas.add(item as DataItem); }
if (item.topic == "processing") { workspaces[current]!.processings.add(item as ProcessingItem); }
if (item.topic == "datacenter") { workspaces[current]!.datacenters.add(item as DataCenterItem); }
if (item.topic == "storage") { workspaces[current]!.storages.add(item as StorageItem); }
if (item.topic == "workflow") { workspaces[current]!.workflows.add(item as WorkflowItem); }
try { _service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {});
} catch (e) { /* */ }
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
}
}
static void removeItem(AbstractItem item) {
items = items.where((element) => element.name != item.name).toList();
try { _service.delete(null, { "id" : item.id.toString(), "rtype" : item.type.toString() });
if (item.topic == "data") { workspaces[current]!.datas.removeWhere( (e) => e.id == item.id); }
if (item.topic == "processing") { workspaces[current]!.processings.removeWhere( (e) => e.id == item.id); }
if (item.topic == "datacenter") { workspaces[current]!.datacenters.removeWhere( (e) => e.id == item.id); }
if (item.topic == "storage") { workspaces[current]!.storages.removeWhere( (e) => e.id == item.id); }
if (item.topic == "workflow") { workspaces[current]!.workflows.removeWhere( (e) => e.id == item.id); }
try { _service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {});
} catch (e) { /* */ }
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
}
static bool hasItemByID(String id) {
return items.where((element) => element.id == id).isNotEmpty;
}
static bool hasItem(AbstractItem item) {
return items.where((element) => element.name == item.name).isNotEmpty;
return items.where((element) => element.id == item.id).isNotEmpty;
}
static void clear() => items.clear();
}

View File

@ -3,6 +3,7 @@ import 'package:oc_front/models/search.dart';
import 'package:oc_front/pages/catalog.dart';
import 'package:oc_front/core/models/workspace_local.dart';
import 'package:oc_front/widgets/items/item_row.dart';
import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart';
GlobalKey<EndDrawerWidgetState> endDrawerKey = GlobalKey<EndDrawerWidgetState>();
class EndDrawerWidget extends StatefulWidget {
@ -33,7 +34,8 @@ class EndDrawerWidgetState extends State<EndDrawerWidget> {
),
),
itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 50,
MenuWorkspaceWidget(simpliest: true, width: 400),
itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 100,
color: Colors.grey.shade300,
child: const Center(child: Text("WORKSPACE IS EMPTY",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white))))

View File

@ -61,7 +61,7 @@ class SearchWidgetState extends State<SearchWidget> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width - 300 - 100,
width: MediaQuery.of(context).size.width - 400 > 0 ? MediaQuery.of(context).size.width - 300 - 100 : MediaQuery.of(context).size.width,
height: 50,
color: Colors.white,
child: TextField(

View File

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

View File

@ -52,9 +52,10 @@ class AppRouter {
description: "View to select & create new workflow.", help: "Workflow only access to your workspace datas. If a an element of your flow is missing, perhaps means it's missing in workspace.",
factory: WorkflowFactory());
static final RouterItem catalogItem = RouterItem(description: "", help: "", route: "catalog/:id", factory: CatalogItemFactory(), args: ["id"]);
static final RouterItem catalog= RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory());
static List<RouterItem> zones = [
RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory()),
catalog,
workflowItem,
RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()),
RouterItem(icon: Icons.dns_outlined, label: "my datacenter", route: "datacenter",

View File

@ -7,9 +7,21 @@ abstract class AbstractService<T extends SerializerDeserializer> {
abstract APIService<T> service;
abstract String subPath;
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(); }
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);
}
}

View File

@ -1,24 +1,11 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.dart';
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/abstract.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/search.dart';
class ItemService<S extends AbstractItem, T extends SerializerDeserializer<S>> extends AbstractService<T> {
@override APIService<T> service = APIService<T>(
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:49618')
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:8087')
);
@override String subPath = "/v1/${getTopic(S)}";
@override Future<APIResponse<T>> all(BuildContext? context) { throw UnimplementedError(); }
@override Future<APIResponse<T>> get(BuildContext? context, String id) {
if (id.contains(",")) { return service.get("$subPath/multi/$id", true, context); }
return service.get("$subPath/$id", true, context);
}
@override Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
return service.post("$subPath/", body, context);
}
@override Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
@override Future<APIResponse<T>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
@override String subPath = "/oc/${getTopic(S)}/";
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.dart';
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/logs.dart';
import 'package:oc_front/models/response.dart';
class LogsService extends AbstractService<LogResults> {
@override APIService<LogResults> service = APIService<LogResults>(
baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:3100')
);
@override String subPath = "/loki/api/v1/";
@override Future<APIResponse<LogResults>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
List<String> v = [];
for (var p in params.keys) {
if (p == "start" || p == "end") { continue; }
v.add("$p=\"${params[p]}\"");
}
return service.get("${subPath}query_range?query={${v.join(", ")}}&start=${params["start"]}&end=${params["end"]}", false, context);
}
@override Future<APIResponse<LogResults>> get(BuildContext? context, String id) {
throw UnimplementedError();
}
@override Future<APIResponse<LogResults>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
throw UnimplementedError();
}
@override Future<APIResponse<LogResults>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
throw UnimplementedError();
}
@override Future<APIResponse<LogResults>> delete(BuildContext? context, String id, Map<String, String> params) {
throw UnimplementedError();
}
}

View File

@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.dart';
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/search.dart';
class ResourceService extends AbstractService<Resource> {
@override APIService<Resource> service = APIService<Resource>(
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:8087')
);
@override String subPath = "/oc/resource/";
@override Future<APIResponse<Resource>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
return service.get("${subPath}search/${words.join("/")}", false, context);
}
@override Future<APIResponse<Resource>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
return throw UnimplementedError();
}
@override Future<APIResponse<Resource>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
return throw UnimplementedError();
}
}

View File

@ -1,19 +0,0 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.dart';
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/search.dart';
class SearchService extends AbstractService<Search> {
@override APIService<Search> service = APIService<Search>(
baseURL: const String.fromEnvironment('SEARCH_HOST', defaultValue: 'http://localhost:49618')
);
@override String subPath = "/v1/search";
@override Future<APIResponse<Search>> all(BuildContext? context) { throw UnimplementedError(); }
@override Future<APIResponse<Search>> get(BuildContext? context, String id) {
return service.get("$subPath/byWord?word=$id", true, context);
}
@override Future<APIResponse<Search>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
@override Future<APIResponse<Search>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
@override Future<APIResponse<Search>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
}

View File

@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.dart';
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/workflow.dart';
class WorkflowExecutionService extends AbstractService<WorkflowExecutions> {
@override APIService<WorkflowExecutions> service = APIService<WorkflowExecutions>(
baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8090')
);
@override String subPath = "/oc/workflow_execution/";
@override Future<APIResponse<WorkflowExecutions>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
return service.get("${subPath}search/${words.join("/")}", false, context);
}
@override Future<APIResponse<WorkflowExecutions>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
return throw UnimplementedError();
}
@override Future<APIResponse<WorkflowExecutions>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
return throw UnimplementedError();
}
}

View File

@ -1,26 +1,10 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.dart';
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/workflow.dart';
class WorflowService extends AbstractService<RawData> {
@override APIService<RawData> service = APIService<RawData>(
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:49618')
class WorflowService extends AbstractService<Workflow> {
@override APIService<Workflow> service = APIService<Workflow>(
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8088')
);
@override String subPath = "/v1/workflow/";
@override Future<APIResponse<RawData>> all(BuildContext? context) {
return service.get(subPath, true, context);
}
@override Future<APIResponse<RawData>> get(BuildContext? context, String id) { throw UnimplementedError(); }
@override Future<APIResponse<RawData>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
String path = "?";
for (var key in params.keys) { path += "$key=${params[key]}&"; }
return service.post("$subPath$path", body, context);
}
@override Future<APIResponse<RawData>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
throw UnimplementedError();
}
@override Future<APIResponse<RawData>> delete(BuildContext? context, Map<String, String> params) {
throw UnimplementedError();
}
@override String subPath = "/oc/workflow/";
}

View File

@ -1,30 +1,10 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.dart';
import 'package:oc_front/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/workspace.dart';
class WorkspaceService extends AbstractService<Workspace> {
@override APIService<Workspace> service = APIService<Workspace>(
baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:49618')
baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:8089')
);
@override String subPath = "/v1/workspace/";
@override Future<APIResponse<Workspace>> all(BuildContext? context) {
return service.get("$subPath/list", true, context);
}
@override Future<APIResponse<Workspace>> get(BuildContext? context, String id) { throw UnimplementedError(); }
@override Future<APIResponse<Workspace>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
String path = "?";
for (var key in params.keys) { path += "$key=${params[key]}&"; }
return service.post("$subPath$path", body, context);
}
@override Future<APIResponse<Workspace>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
throw UnimplementedError();
}
@override Future<APIResponse<Workspace>> delete(BuildContext? context, Map<String, String> params) {
String path = "?";
for (var key in params.keys) { path += "$key=${params[key]}&"; }
return service.delete("$subPath$path", context);
}
@override String subPath = "/oc/workspace/";
}

View File

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

View File

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

116
lib/models/logs.dart Normal file
View File

@ -0,0 +1,116 @@
import 'package:oc_front/models/abstract.dart';
import 'package:json_string/json_string.dart';
class LogResults extends SerializerDeserializer<LogResults> {
String? status;
LogsResult? data;
LogResults({
this.status,
this.data,
});
String getID() {
return "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return LogResults(); }
return LogResults(
status: json.containsKey("status") ? json["status"] : "",
data: json.containsKey("data") ? LogsResult().deserialize(json["data"]) : null,
);
}
@override Map<String, dynamic> serialize() {
return { };
}
}
class LogsResult extends SerializerDeserializer<LogsResult> {
List<Logs> result;
LogsResult({
this.result = const [],
});
String getID() {
return "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return LogsResult(); }
return LogsResult(
result: json.containsKey("result") ? fromListJson(json["result"], Logs()) : [],
);
}
@override Map<String, dynamic> serialize() {
return { };
}
}
class Logs extends SerializerDeserializer<Logs> {
String? level;
List<Log> logs = [];
Logs({
this.level,
});
String getID() {
return "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Logs(); }
return Logs(
level: json.containsKey("stream") && (json["stream"] as Map<String, dynamic>).containsKey("level") ? json["stream"]["level"] : "",
);
}
@override Map<String, dynamic> serialize() {
return { };
}
}
class Log extends SerializerDeserializer<Log> {
DateTime? timestamp;
String? message;
String? level;
Map<String, dynamic> map = {};
Log({
this.timestamp,
this.message,
this.level
});
String getID() {
return "";
}
String getMessage(String mess) {
var jsonString = mess;
try {
var j = JsonString(mess.replaceAll("\\", "")).decodedValue as Map<String, dynamic>;
map = j;
if (j["Status"] == "Pending") {
jsonString = "${j["Name"]} : [${j["Namespace"]}] Status: ${j["Status"]}... \nCreated at ${j["Created"].toString().replaceAllMapped(RegExp(r'\(\w+\)'), (match) { return ''; }).replaceAllMapped(RegExp(r'\+\w+'), (match) { return ''; })}";
} else {
jsonString = "${j["Name"]} : [${j["Namespace"]}] ${j["Status"]} ${j["Progress"]} (${j["Duration"].toString().replaceAll("seconds", "s")})\nStarted at ${j["Created"].toString().replaceAllMapped(RegExp(r'\(\w+\)'), (match) { return ''; }).replaceAllMapped(RegExp(r'\+\w+'), (match) { return ''; })}";
}
} on JsonFormatException catch (e) { /* */ }
message = jsonString;
return jsonString;
}
@override deserialize(dynamic json) {
try { json = json as List<dynamic>;
} catch (e) { return Log(); }
return Log(
timestamp: json.isNotEmpty ? DateTime.parse(json[0]) : null,
message: json.length > 1 ? getMessage(json[1].toString()) : null,
);
}
@override Map<String, dynamic> serialize() { return { }; }
}

View File

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

View File

@ -1,6 +1,7 @@
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:oc_front/models/abstract.dart';
const List<ComputingItem> _emptyComputing = [];
const List<ProcessingItem> _emptyComputing = [];
const List<DataItem> _emptyData = [];
const List<DataCenterItem> _emptyDataCenter = [];
const List<StorageItem> _emptyStorage = [];
@ -11,248 +12,539 @@ class Search extends SerializerDeserializer<Search> {
this.data = _emptyData,
this.storage = _emptyStorage,
});
List<ComputingItem> computing;
List<ProcessingItem> computing;
List<DataCenterItem> datacenter;
List<DataItem> data;
List<StorageItem> storage;
@override deserialize(dynamic json) {
json = json as Map<String, dynamic>;
return Search(
computing: json.containsKey("computing") ? fromListJson(json["computing"], ComputingItem()) : [],
computing: json.containsKey("processing") ? fromListJson(json["processing"], ProcessingItem()) : [],
datacenter: json.containsKey("datacenter") ? fromListJson(json["datacenter"], DataCenterItem()) : [],
data: json.containsKey("data") ? fromListJson(json["data"], DataItem()) : [],
storage: json.containsKey("storage") ? fromListJson(json["storage"], StorageItem()) : [],
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"processing": toListJson<ProcessingItem>(computing),
"datacenter": toListJson<DataCenterItem>(datacenter),
"data": toListJson<DataItem>(data),
"storage": toListJson<StorageItem>(storage),
};
}
const List<String> _empty = [];
abstract class AbstractItem {
class Resource implements SerializerDeserializer<Resource> {
List<DataItem> datas = [];
List<ProcessingItem> processings = [];
List<StorageItem> storages = [];
List<DataCenterItem> datacenters = [];
List<WorkflowItem> workflows = [];
Resource({
this.datas = const [],
this.processings = const [],
this.storages = const [],
this.datacenters = const [],
this.workflows = const [],
});
@override Resource deserialize(json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Resource(); }
return Resource(
datacenters: json.containsKey("datacenter_resource") ? fromListJson(json["datacenter_resource"], DataCenterItem()) : [],
datas: json.containsKey("data_resource") ? fromListJson(json["data_resource"], DataItem()) : [],
processings: json.containsKey("processing_resource") ? fromListJson(json["processing_resource"], ProcessingItem()) : [],
storages: json.containsKey("storage_resource") ? fromListJson(json["storage_resource"], StorageItem()) : [],
workflows: json.containsKey("workflow_resource") ? fromListJson(json["workflow_resource"], WorkflowItem()) : [],
);
}
@override Map<String, dynamic> serialize() {
return {
"datacenter_resource": toListJson<DataCenterItem>(datacenters),
"data_resource": toListJson<DataItem>(datas),
"processing_resource": toListJson<ProcessingItem>(processings),
"storage_resource": toListJson<StorageItem>(storages),
"workflow_resource": toListJson<WorkflowItem>(workflows),
};
}
}
abstract class AbstractItem<T extends FlowData> extends FlowData implements SerializerDeserializer<T> {
String? id;
String? name;
String? logo;
String? type;
String? owner;
String? ownerLogo;
String? source;
String? description;
String? shortDescription;
double? price;
String? licence;
List<dynamic> inputs = [];
List<dynamic> outputs = [];
ResourceModel? model;
String topic = "";
AbstractItem({
this.id,
this.name,
this.logo,
this.owner,
this.ownerLogo,
this.price,
this.source,
this.licence,
this.description,
this.model,
this.shortDescription,
this.inputs = const [],
this.outputs = const [],
});
@override String getID() {
return id ?? "";
}
@override String getName() {
return name ?? "";
}
}
class Model extends SerializerDeserializer<Model> {
dynamic value;
String? type;
bool readonly = false;
Model({
this.value,
this.type,
this.readonly = false,
});
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Model(); }
return Model(
value: json.containsKey("value") ? json["value"] : null,
type: json.containsKey("type") ? json["type"] : null,
readonly: json.containsKey("readonly") ? json["readonly"] : false,
);
}
@override Map<String, dynamic> serialize() => {
"value": value,
"type": type,
"readonly": readonly,
};
}
class ResourceModel extends SerializerDeserializer<ResourceModel> {
String? id;
String? type;
Map<String, Model>? model;
ResourceModel({
this.id,
this.type,
this.model,
});
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return ResourceModel(); }
return ResourceModel(
id: json.containsKey("id") ? json["id"] : null,
type: json.containsKey("type") ? json["type"] : null,
model: json.containsKey("model") ? fromMapJson(json["model"], Model()) : {},
);
}
@override Map<String, dynamic> serialize() => {
"id": id,
"type": type,
"model": toMapJson<Model>(model ?? {}),
};
}
Type? getTopicType(String topic) {
if (topic == "computing") { return ComputingItem; }
if (topic == "processing") { return ProcessingItem; }
else if (topic == "data") { return DataItem; }
else if (topic == "datacenter") { return DataCenterItem; }
else if (topic == "storage") { return StorageItem; }
else if (topic == "workflow") { return WorkflowItem; }
else { return null; }
}
String getTopic(Type type) {
if (type == ComputingItem) { return "computing"; }
if (type == AbstractItem) { return "resource"; }
if (type == ProcessingItem) { return "processing"; }
if (type == DataItem) { return "data"; }
if (type == DataCenterItem) { return "datacenter"; }
if (type == StorageItem) { return "storage"; }
if (type == WorkflowItem) { return "workflow"; }
return "";
}
bool isComputing(String topic) => topic == "computing";
bool isComputing(String topic) => topic == "processing";
bool isData(String topic) => topic == "data";
bool isDataCenter(String topic) => topic == "datacenter";
bool isStorage(String topic) => topic == "storage";
bool isWorkflow(String topic) => topic == "workflow";
class ComputingItem extends SerializerDeserializer<ComputingItem> implements AbstractItem {
ComputingItem({
class ProcessingItem extends SerializerDeserializer<ProcessingItem> implements AbstractItem<ProcessingItem> {
ProcessingItem({
this.id,
this.name,
this.logo,
this.type,
this.owner,
this.ownerLogo,
this.price,
this.image,
this.command,
this.source,
this.licence,
this.description,
this.requirements,
this.ports = _empty,
this.shortDescription,
this.dinputs = _empty,
this.doutputs = _empty,
this.arguments = _empty,
this.environment = _empty,
this.inputs = _empty,
this.outputs = _empty,
this.cpus = const [],
this.gpus = const [],
this.ram,
this.storage,
this.parrallel = false,
this.scallingModel,
this.diskIO,
this.model,
});
@override ResourceModel? model;
@override String? id;
@override String? name;
@override String? logo;
@override String? type;
@override String? source;
@override String? ownerLogo;
@override String? owner;
@override String topic = "computing";
double? price;
String? image;
String? command;
String? licence;
List<dynamic> ports;
List<dynamic> dinputs;
List<dynamic> doutputs;
List<dynamic> arguments;
@override String topic = "processing";
@override double? price;
@override String? licence;
@override List<dynamic> inputs;
@override List<dynamic> outputs;
@override String? description;
@override String? shortDescription;
List<dynamic> environment;
ExecRequirements? requirements;
// Special Attributes
List<CPU> cpus = [];
List<GPU> gpus = [];
RAM? ram;
int? storage;
bool parrallel = false;
int? scallingModel;
String? diskIO;
@override String getID() {
return id ?? "";
}
@override String getName() {
return name ?? "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return ComputingItem(); }
return ComputingItem(
id: json.containsKey("ID") ? json["ID"] : null,
} catch (e) { return ProcessingItem(); }
return ProcessingItem(
id: json.containsKey("id") ? json["id"] : null,
name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : null,
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
image: json.containsKey("image") ? json["image"] : null,
command: json.containsKey("command") ? json["command"] : null,
licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : null,
ports: json["ports"] ?? [],
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
dinputs: json["dinputs"] ?? [],
doutputs: json["doutputs"] ?? [],
arguments: json["arguments"] ?? [],
environment: json["environment"] ?? [],
requirements: json.containsKey("requirements") ? ExecRequirements().deserialize(json["execution_requirements"]) : null,
inputs: json["inputs"] ?? [],
outputs: json["outputs"] ?? [],
source: json.containsKey("source") ? json["source"] : null,
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
cpus: json.containsKey("cpus") ? fromListJson(json["cpus"], CPU()) : [],
gpus: json.containsKey("gpus") ? fromListJson(json["gpus"], GPU()) : [],
ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null,
storage: json.containsKey("storage") ? json["storage"] : null,
parrallel: json.containsKey("parrallel") ? json["parrallel"] : false,
scallingModel: json.containsKey("scalling_model") ? json["scalling_model"] : null,
diskIO: json.containsKey("disk_io") ? json["disk_io"] : null,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"id": id,
"name": name,
"logo": logo,
"owner": owner,
"owner_logo": ownerLogo,
"price": price,
"licence": licence,
"description": description,
"short_description": shortDescription,
"inputs": inputs,
"outputs": outputs,
"source": source,
"resource_model": model?.serialize(),
"cpus": toListJson<CPU>(cpus),
"gpus": toListJson<GPU>(gpus),
"ram": ram?.serialize(),
"storage": storage,
"parrallel": parrallel,
"scalling_model": scallingModel,
"disk_io": diskIO,
};
}
class ExecRequirements extends SerializerDeserializer<ExecRequirements> {
ExecRequirements({
this.ram,
this.cpus,
this.gpus,
this.diskIO,
this.scallingModel,
this.parallel = false,
class WorkflowItem extends SerializerDeserializer<WorkflowItem> implements AbstractItem<WorkflowItem> {
WorkflowItem({
this.id,
this.name,
this.logo,
this.owner,
this.ownerLogo,
this.price,
this.source,
this.licence,
this.description,
this.shortDescription,
this.inputs = _empty,
this.outputs = _empty,
this.model,
this.workflowID,
});
double? ram;
double? cpus;
double? gpus;
String? diskIO;
bool parallel = false;
double? scallingModel;
@override ResourceModel? model;
@override String? id;
@override String? name;
@override String? logo;
@override String? source;
@override String? ownerLogo;
@override String? owner;
@override String topic = "workflow";
@override double? price;
@override String? licence;
@override List<dynamic> inputs;
@override List<dynamic> outputs;
@override String? description;
@override String? shortDescription;
String? workflowID;
@override String getID() {
return id ?? "";
}
@override String getName() {
return name ?? "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return ExecRequirements(); }
return ExecRequirements(
ram: json.containsKey("ram") ? json["ram"]?.toDouble() : null,
cpus: json.containsKey("cpus") ? json["cpus"]?.toDouble() : null,
gpus: json.containsKey("gpus") ? json["gpus"]?.toDouble() : null,
diskIO: json.containsKey("disk_io") ? json["disk_io"] : null,
scallingModel: json.containsKey("scaling_model") ? json["scaling_model"]?.toDouble() : null,
parallel: json.containsKey("parallel") ? json["parallel"] : false,
} catch (e) { return WorkflowItem(); }
return WorkflowItem(
id: json.containsKey("id") ? json["id"] : null,
name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null,
owner: json.containsKey("owner") ? json["owner"] : null,
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : null,
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
inputs: json["inputs"] ?? [],
outputs: json["outputs"] ?? [],
source: json.containsKey("source") ? json["source"] : null,
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
workflowID: json.containsKey("workflow_id") ? json["workflow_id"] : null,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"id": id,
"name": name,
"logo": logo,
"owner": owner,
"owner_logo": ownerLogo,
"price": price,
"licence": licence,
"description": description,
"short_description": shortDescription,
"inputs": inputs,
"outputs": outputs,
"source": source,
"resource_model": model?.serialize(),
"workflow_id": workflowID,
};
}
class DataItem extends SerializerDeserializer<DataItem> implements AbstractItem {
class DataItem extends SerializerDeserializer<DataItem> implements AbstractItem<DataItem> {
DataItem({
this.id,
this.name,
this.logo,
this.type,
this.dtype,
this.owner,
this.example,
this.location,
this.ownerLogo,
this.price,
this.source,
this.licence,
this.description,
this.protocol = _empty,
this.shortDescription,
this.inputs = _empty,
this.outputs = _empty,
this.model,
this.protocols = const [],
this.dataType,
this.exemple,
});
@override String? id;
@override String? name;
@override String? logo;
@override String? type;
@override String topic = "data";
String? dtype;
String? example;
String? location;
@override String? description;
List<dynamic> protocol;
@override String? shortDescription;
@override String? source;
@override String? ownerLogo;
@override String? owner;
@override String topic = "data";
@override double? price;
@override String? licence;
@override List<dynamic> inputs;
@override List<dynamic> outputs;
@override String? description;
@override String? shortDescription;
@override ResourceModel? model;
// Special Attributes
List<String> protocols = [];
String? dataType;
String? exemple;
@override String getName() {
return name ?? "";
}
@override String getID() {
return id ?? "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return DataItem(); }
return DataItem(
id: json.containsKey("ID") ? json["ID"] : null,
id: json.containsKey("id") ? json["id"] : null,
name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : null,
dtype: json.containsKey("dtype") ? json["dtype"] : null,
example: json.containsKey("example") ? json["example"] : null,
location: json.containsKey("location") ? json["location"] : null,
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : null,
protocol: json["protocol"] ?? [],
shortDescription: json.containsKey("short_description") ? json["short_description"] : null
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
inputs: json["inputs"] ?? [],
outputs: json["outputs"] ?? [],
source: json.containsKey("source") ? json["source"] : null,
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
protocols: json.containsKey("protocols") ? json["protocols"] : [],
dataType: json.containsKey("data_type") ? json["data_type"] : null,
exemple: json.containsKey("exemple") ? json["exemple"] : null,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"id": id,
"name": name,
"logo": logo,
"owner": owner,
"owner_logo": ownerLogo,
"price": price,
"licence": licence,
"description": description,
"short_description": shortDescription,
"inputs": inputs,
"outputs": outputs,
"source": source,
"resource_model": model?.serialize(),
"protocols": protocols,
"data_type": dataType,
"exemple": exemple,
};
}
const List<GPU> _emptyGPU = [];
class DataCenterItem extends SerializerDeserializer<DataCenterItem> implements AbstractItem {
class DataCenterItem extends SerializerDeserializer<DataCenterItem> implements AbstractItem<DataCenterItem> {
DataCenterItem({
this.id,
this.cpu,
this.ram,
this.name,
this.logo,
this.type,
this.owner,
this.acronym,
this.bookingPrice,
this.ownerLogo,
this.price,
this.source,
this.licence,
this.description,
this.hosts = _empty,
this.gpus = _emptyGPU,
this.shortDescription,
this.inputs = _empty,
this.outputs = _empty,
this.model,
this.cpus = const [],
this.gpus = const [],
this.ram,
});
CPU? cpu;
RAM? ram;
@override String? id;
@override String? name;
@override String? logo;
@override String? type;
@override String? source;
@override String? ownerLogo;
@override String? owner;
@override String topic = "datacenter";
String? acronym;
List<GPU> gpus = [];
@override double? price;
@override String? licence;
@override List<dynamic> inputs;
@override List<dynamic> outputs;
@override String? description;
List<dynamic> hosts;
double? bookingPrice;
@override String? shortDescription;
@override ResourceModel? model;
// Special Attributes
List<CPU> cpus = [];
List<GPU> gpus = [];
RAM? ram;
@override String getID() {
return id ?? "";
}
@override String getName() {
return name ?? "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return DataCenterItem(); }
return DataCenterItem(
id: json.containsKey("ID") ? json["ID"] : null,
ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null,
cpu: json.containsKey("cpu") ? CPU().deserialize(json["cpu"]) : null,
acronym: json.containsKey("acronym") ? json["acronym"] : null,
id: json.containsKey("id") ? json["id"] : null,
name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : null,
bookingPrice: json.containsKey("bookingPrice") ? json["bookingPrice"]?.toDouble() : null,
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : null,
hosts: json["hosts"] ?? [],
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
gpus: json.containsKey("gpus") ? fromListJson(json["gpus"] ?? [], GPU()) : [],
inputs: json["inputs"] ?? [],
outputs: json["outputs"] ?? [],
source: json.containsKey("source") ? json["source"] : null,
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
cpus: json.containsKey("cpus") ? fromListJson(json["cpus"], CPU()) : [],
gpus: json.containsKey("gpus") ? fromListJson(json["gpus"], GPU()) : [],
ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"id": id,
"name": name,
"logo": logo,
"owner": owner,
"owner_logo": ownerLogo,
"price": price,
"licence": licence,
"description": description,
"short_description": shortDescription,
"inputs": inputs,
"outputs": outputs,
"source": source,
"resource_model": model?.serialize(),
"cpus": toListJson<CPU>(cpus),
"gpus": toListJson<GPU>(gpus),
"ram": ram?.serialize(),
};
}
class CPU extends SerializerDeserializer<CPU> {
CPU({
@ -279,7 +571,13 @@ class CPU extends SerializerDeserializer<CPU> {
shared: json.containsKey("shared") ? json["shared"] : false,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"cores": cores,
"platform": platform,
"architecture": architecture,
"minimumMemory": minimumMemory,
"shared": shared,
};
}
class GPU extends SerializerDeserializer<GPU> {
GPU({
@ -303,7 +601,12 @@ class GPU extends SerializerDeserializer<GPU> {
tensorCores: json.containsKey("tensor_cores") ? json["tensor_cores"]?.toDouble() : null,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"cuda_cores": cudaCores,
"memory": memory,
"model": model,
"tensor_cores": tensorCores,
};
}
class RAM extends SerializerDeserializer<RAM> {
RAM({
@ -321,61 +624,108 @@ class RAM extends SerializerDeserializer<RAM> {
size: json.containsKey("size") ? json["size"]?.toDouble() : null,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"ecc": ecc,
"size": size,
};
}
class StorageItem extends SerializerDeserializer<StorageItem> implements AbstractItem {
class StorageItem extends SerializerDeserializer<StorageItem> implements AbstractItem<StorageItem> {
StorageItem({
this.id,
this.url,
this.size,
this.name,
this.logo,
this.type,
this.owner,
this.acronym,
this.throughput,
this.redundancy,
this.ownerLogo,
this.price,
this.source,
this.licence,
this.description,
this.bookingPrice,
this.shortDescription,
this.inputs = _empty,
this.outputs = _empty,
this.acronym,
this.type,
this.size,
this.url,
this.encryption = false,
this.redundancy,
this.throughput,
this.model,
});
@override String? id;
String? url;
@override String? name;
@override String? logo;
@override String? type;
@override String? id;
@override String? name;
@override String? logo;
@override String? source;
@override String? ownerLogo;
@override String? owner;
@override String topic = "storage";
double? size;
@override String? owner;
@override double? price;
@override String? licence;
@override List<dynamic> inputs;
@override List<dynamic> outputs;
@override String? description;
@override String? shortDescription;
@override ResourceModel? model;
// special attributes
String? acronym;
String? type;
int? size;
String? url;
bool encryption = false;
String? redundancy;
String? throughput;
@override String? description;
double? bookingPrice;
bool encryption = false;
@override String? shortDescription;
@override String getName() {
return name ?? "";
}
@override String getID() {
return id ?? "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return StorageItem(); }
return StorageItem(
id: json.containsKey("ID") ? json["ID"] : null,
url: json.containsKey("URL") ? json["URL"] : null,
size: json.containsKey("size") ? json["size"]?.toDouble() : null,
id: json.containsKey("id") ? json["id"] : null,
name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : null,
acronym: json.containsKey("DCacronym") ? json["DCacronym"] : null,
bookingPrice: json.containsKey("bookingPrice") ? json["bookingPrice"]?.toDouble() : null,
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : null,
throughput: json.containsKey("throughput") ? json["throughput"] : [],
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
redundancy: json.containsKey("redundancy") ? json["redundancy"] : [],
inputs: json["inputs"] ?? [],
outputs: json["outputs"] ?? [],
source: json.containsKey("source") ? json["source"] : null,
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
acronym: json.containsKey("acronym") ? json["acronym"] : null,
type: json.containsKey("type") ? json["type"] : null,
size: json.containsKey("size") ? json["size"] : null,
url: json.containsKey("url") ? json["url"] : null,
encryption: json.containsKey("encryption") ? json["encryption"] : false,
redundancy: json.containsKey("redundancy") ? json["redundancy"] : null,
throughput: json.containsKey("throughput") ? json["throughput"] : null,
);
}
@override Map<String, dynamic> serialize() => {};
@override Map<String, dynamic> serialize() => {
"id": id,
"name": name,
"logo": logo,
"owner": owner,
"owner_logo": ownerLogo,
"price": price,
"licence": licence,
"description": description,
"short_description": shortDescription,
"inputs": inputs,
"outputs": outputs,
"source": source,
"resource_model": model?.serialize(),
"acronym": acronym,
"type": type,
"size": size,
"url": url,
"encryption": encryption,
"redundancy": redundancy,
"throughput": throughput,
};
}

559
lib/models/workflow.dart Normal file
View File

@ -0,0 +1,559 @@
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:oc_front/core/models/workspace_local.dart';
import 'package:oc_front/models/abstract.dart';
import 'package:oc_front/models/search.dart';
class WorkflowExecutions extends SerializerDeserializer<WorkflowExecutions> {
List<WorkflowExecution> executions = [];
String? executionData;
int? status;
String? workflowId;
WorkflowExecutions({
this.executions = const [],
});
@override deserialize(dynamic json) {
try { json = json as List<dynamic>;
} catch (e) { return WorkflowExecutions(); }
return WorkflowExecutions(
executions: fromListJson(json, WorkflowExecution()),
);
}
@override Map<String, dynamic> serialize() {
return {};
}
}
class WorkflowExecution extends SerializerDeserializer<WorkflowExecution> {
String? id;
String? name;
String? executionData;
String? endDate;
int? status;
String? workflowId;
WorkflowExecution({
this.id,
this.executionData,
this.status,
this.workflowId,
this.name,
this.endDate,
});
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return WorkflowExecution(); }
return WorkflowExecution(
id: json.containsKey("id") ? json["id"] : "",
endDate: json.containsKey("end_date") ? json["end_date"] : "",
executionData: json.containsKey("execution_date") ? json["execution_date"] : "",
status: json.containsKey("status") ? json["status"] : 1,
workflowId: json.containsKey("workflow_id") ? json["workflow_id"] : "",
name: json.containsKey("name") ? json["name"] : "",
);
}
@override Map<String, dynamic> serialize() {
return {
"id": id,
"name": name,
"end_date": endDate,
"execution_data": executionData,
"status": status,
"workflow_id": workflowId,
};
}
}
class Workflow extends SerializerDeserializer<Workflow> {
String? id;
String? name;
List<dynamic> data;
List<dynamic> datacenter;
List<dynamic> storage;
List<dynamic> processing;
List<dynamic> workflows;
Graph? graph;
Scheduler? schedule;
Workflow({
this.id,
this.name = "",
this.data = const [],
this.datacenter = const [],
this.storage = const [],
this.processing = const [],
this.workflows = const [],
this.graph,
this.schedule,
});
String getID() {
return id ?? "";
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Workflow(); }
return Workflow(
id: json.containsKey("id") ? json["id"] : "",
name: json.containsKey("name") ? json["name"] : "",
workflows: json.containsKey("workflows") ? json["workflows"] : [],
processing: json.containsKey("processings") ? json["processings"] : [],
datacenter: json.containsKey("datacenters") ? json["datacenters"] : [],
data: json.containsKey("datas") ? json["datas"] : [],
storage: json.containsKey("storages") ? json["storages"] : [],
graph: json.containsKey("graph") ? Graph().deserialize(json["graph"]) : null,
schedule: json.containsKey("schedule") ? Scheduler().deserialize(json["schedule"]) : null,
);
}
@override Map<String, dynamic> serialize() {
var obj = {
"id": id,
"name": name,
"datas": data,
"datacenters" : datacenter,
"storages": storage,
"processings": processing,
"workflows": workflows,
"schedule": schedule?.serialize(),
};
if (graph != null) {
obj["graph"] = graph!.serialize();
}
return obj;
}
void fromDashboard(Map<String, dynamic> j) {
id = j["id"];
name = j["name"];
if (j.containsKey("graph")) {
graph = Graph();
graph!.fromDashboard(j["graph"]);
}
if (j.containsKey("schedule")) {
schedule = Scheduler();
schedule!.fromDashboard(j["schedule"]);
}
}
Map<String, dynamic> toDashboard() {
return {
"id": id,
"name": name,
"graph": graph?.toDashboard(),
"schedule": schedule?.toDashboard(),
};
}
}
class Scheduler extends SerializerDeserializer<Scheduler> {
String? id;
String? name;
String? cron;
DateTime? start;
DateTime? end;
Scheduler({
this.id,
this.name,
this.cron,
this.start,
this.end
});
void fromDashboard(Map<String, dynamic> j) {
id = j["id"];
name = j["name"];
cron = j["cron"];
start = DateTime.parse(j["start"]);
if (j.containsKey("end") && j["end"] != null) {
end = DateTime.parse(j["end"]);
}
}
Map<String, dynamic> toDashboard() {
return {
"id": id,
"name": name,
"cron": cron,
"start": start?.toIso8601String(),
"end": end?.toIso8601String(),
};
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Scheduler(); }
return Scheduler(
id: json.containsKey("id") ? json["id"] : null,
name: json.containsKey("name") ? json["name"] : "",
cron: json.containsKey("cron") ? json["cron"] : "",
start: json.containsKey("start") ? DateTime.parse(json["start"]) : null,
end: json.containsKey("end") ? DateTime.parse(json["end"]) : null,
);
}
@override Map<String, dynamic> serialize() => {
"id": id,
"name": name,
"cron": cron ?? "",
"start": start?.toIso8601String(),
"end": end?.toIso8601String(),
};
}
class Graph extends SerializerDeserializer<Graph> {
double zoom;
Map<String, GraphItem> items = {};
List<GraphLink> links = [];
Graph({
this.zoom = 1,
this.items = const {},
this.links = const [],
});
void fromDashboard(Map<String, dynamic> j) {
items = {};
for (var el in (j["elements"] as Map<dynamic, dynamic>).values) {
var d = GraphItem();
d.fromDashboard(el as Map<String, dynamic>);
items[d.id ?? ""] = d;
}
links = (j["arrows"] as List<dynamic>).map( (el) {
var d = GraphLink();
d.fromDashboard(el);
return d;
}).toList();
j["zoom"] = zoom;
}
Map<String, dynamic> toDashboard() {
List<Map<String, dynamic>> elements = [];
List<Map<String, dynamic>> arrows = [];
for (var el in items.values) {
elements.add(el.toDashboard());
}
for (var l in links) {
arrows.add(l.toDashboard());
}
return {
"zoom": zoom,
"elements": elements,
"arrows": arrows,
};
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Graph(); }
return Graph(
zoom: json.containsKey("zoom") ? double.parse(json["zoom"].toString()) : 0,
links: json.containsKey("links") ? fromListJson(json["links"], GraphLink()) : [],
items: json.containsKey("items") ? fromMapJson<GraphItem>(json["items"], GraphItem()) : {},
);
}
@override Map<String, dynamic> serialize() => {
"zoom": zoom,
"items": toMapJson(items),
"links": toListJson(links),
};
}
class GraphLink extends SerializerDeserializer<GraphLink> {
Position? source;
Position? destination;
GraphLinkStyle? style;
GraphLink({
this.source,
this.destination,
this.style,
});
void fromDashboard(Map<String, dynamic> j) {
source = Position(id: j["from"]["id"], x: j["from"]["x"], y: j["from"]["y"]);
destination = Position(id: j["to"]["id"], x: j["to"]["x"], y: j["to"]["y"]);
style = GraphLinkStyle();
style!.fromDashboard(j["params"]);
}
Map<String, dynamic> toDashboard() {
return {
"from": {
"id": source?.id ?? "",
"x" : source?.x ?? 0,
"y": source?.y ?? 0,
},
"to": {
"id": destination?.id ?? "",
"x" : destination?.x ?? 0,
"y": destination?.y ?? 0,
},
"params": style?.toDashboard(),
};
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return GraphLink(); }
return GraphLink(
source: json.containsKey("source") ? Position().deserialize(json["source"]) : null,
destination: json.containsKey("destination") ? Position().deserialize(json["destination"]) : null,
style: json.containsKey("style") ? GraphLinkStyle().deserialize(json["style"]) : null,
);
}
@override Map<String, dynamic> serialize() {
var obj = <String, dynamic>{};
if (source != null) {
obj["source"] = source!.serialize();
}
if (destination != null) {
obj["destination"] = destination!.serialize();
}
if (style != null) {
obj["style"] = style!.serialize();
}
return obj;
}
}
class GraphLinkStyle extends SerializerDeserializer<GraphLinkStyle> {
Color color = Colors.black;
double stroke = 1;
double tension = 23;
double headRadius = 10;
double dashWidth = 0;
double dashSpace = 0;
double startArrowWidth = 1;
double endArrowWidth = 10;
Position? startArrow;
Position? endArrow;
ArrowStyle arrowStyle = ArrowStyle.curve;
ArrowDirection arrowDirection = ArrowDirection.forward;
GraphLinkStyle({
this.color = Colors.black,
this.stroke = 1,
this.tension = 23,
this.headRadius = 10,
this.dashWidth = 0,
this.dashSpace = 0,
this.startArrowWidth = 10,
this.endArrowWidth = 10,
this.startArrow,
this.endArrow,
this.arrowStyle = ArrowStyle.curve,
this.arrowDirection = ArrowDirection.forward
});
void fromDashboard(Map<String, dynamic> j) {
dashSpace = j["dash_space"];
dashWidth = j["dash_width"];
endArrowWidth = j["backward_arrow_width"];
startArrowWidth = j["forward_arrow_width"];
stroke = j["thickness"];
arrowDirection = ArrowDirection.values.firstWhere((element) => element.index == j["direction"]);
headRadius = j["head_radius"];
color = Color(j["color"]);
arrowStyle = ArrowStyle.values.firstWhere((element) => element.index == j["arrow_style"]);
tension = j["tension"];
startArrow = Position(x: j["start_arrow_position_x"], y: j["start_arrow_position_y"]);
endArrow = Position(x: j["end_arrow_position_x"], y: j["end_arrow_position_y"]);
}
Map<String, dynamic> toDashboard() {
return {
"dash_space": dashSpace,
"dash_width": dashWidth,
"backward_arrow_width": endArrowWidth,
"forward_arrow_width": startArrowWidth,
"thickness": stroke,
"direction": arrowDirection.index,
"head_radius": headRadius,
"tail_length": 25.0,
"color": int.parse(color.toHexString(), radix: 16),
"arrow_style" : arrowStyle.index,
"tension" : tension,
"start_arrow_position_x": startArrow?.x ?? 0,
"start_arrow_position_y": startArrow?.y ?? 0,
"end_arrow_position_x": endArrow?.x ?? 0,
"end_arrow_position_y": endArrow?.y ?? 0,
};
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return GraphLinkStyle(); }
return GraphLinkStyle(
color: json.containsKey("color") ? Color(json["color"] as int) : Colors.black,
stroke: json.containsKey("stroke") ? double.parse(json["stroke"].toString()) : 0,
tension: json.containsKey("tension") ? double.parse(json["tension"].toString()) : 0,
headRadius: json.containsKey("head_radius") ? double.parse(json["head_radius"].toString()) : 0,
dashWidth: json.containsKey("dash_width") ? double.parse(json["dash_width"].toString()) : 0,
dashSpace: json.containsKey("dash_space") ? double.parse(json["dash_space"].toString()) : 0,
startArrow: json.containsKey("start_arrow") ? Position().deserialize(json["start_arrow"]) : null,
endArrow: json.containsKey("end_arrow") ? Position().deserialize(json["end_arrow"]) : null,
arrowDirection: json.containsKey("arrow_direction") ? ArrowDirection.values.firstWhere((el) => el.index == json["arrow_direction"]) : ArrowDirection.forward,
arrowStyle: json.containsKey("arrow_style") ? ArrowStyle.values.firstWhere((el) => el.index == json["arrow_style"]) : ArrowStyle.curve,
startArrowWidth: json.containsKey("start_arrow_width") ? double.parse(json["start_arrow_width"].toString()) : 0,
endArrowWidth: json.containsKey("end_arrow_width") ? double.parse(json["end_arrow_width"].toString()) : 0,
);
}
@override Map<String, dynamic> serialize() {
var obj = <String, dynamic> {
"color" : int.parse(color.toHexString(), radix: 16),
"stroke" : stroke,
"tension" : tension,
"head_radius" : headRadius,
"dash_width" : dashWidth,
"dash_space" : dashSpace,
"arrow_direction" : arrowDirection.index,
"arrow_style" : arrowStyle.index,
"start_arrow_width" : startArrowWidth,
"end_arrow_width" : endArrowWidth,
};
if (startArrow != null) {
obj["start_arrow"] = startArrow!.serialize();
}
if (endArrow != null) {
obj["end_arrow"] = endArrow!.serialize();
}
return obj;
}
}
class GraphItem extends SerializerDeserializer<GraphItem> {
String? id;
double? width;
double? height;
Position? position;
DataItem? data;
ProcessingItem? processing;
StorageItem? storage;
DataCenterItem? datacenter;
WorkflowItem? workflow;
GraphItem({
this.id,
this.width,
this.height,
this.position,
this.data,
this.processing,
this.storage,
this.datacenter,
this.workflow,
});
void fromDashboard(Map<String, dynamic> j) {
id = j["id"];
position = Position(x: j["x"], y: j["y"]);
width = j["width"];
height = j["height"];
var abs = WorkspaceLocal.getItem(j["element"]?["id"] ?? "", true) as AbstractItem<FlowData>?;
if (abs != null) {
if (abs.topic == "data") {
data = DataItem().deserialize(abs.serialize());
data!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
}
if (abs.topic == "processing") {
processing = ProcessingItem().deserialize(abs.serialize());
processing!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
}
if (abs.topic == "datacenter") {
datacenter = DataCenterItem().deserialize(abs.serialize());
datacenter!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
}
if (abs.topic == "storage") {
storage = StorageItem().deserialize(abs.serialize());
storage!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
}
if (abs.topic == "workflow") {
workflow = WorkflowItem().deserialize(abs.serialize());
workflow!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
}
}
}
Map<String, dynamic> toDashboard() {
Map<String, dynamic> element = {};
for(var el in [data, processing, storage, datacenter, workflow]) {
if (el != null && el.getID() != "") {
element = el.serialize();
break;
}
}
return {
"id": id,
"x": (position?.x ?? 0),
"y": (position?.y ?? 0),
"width": width ?? 0,
"height": height ?? 0,
"element": element,
};
}
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return GraphItem(); }
return GraphItem(
id: json.containsKey("id") ? json["id"] : null,
width: json.containsKey("width") ? double.parse(json["width"].toString()) : null,
height: json.containsKey("height") ? double.parse(json["height"].toString()) : null,
position: json.containsKey("position") ? Position().deserialize(json["position"]) : null,
data: json.containsKey("data") ? DataItem().deserialize(json["data"]) : null,
processing: json.containsKey("processing") ? ProcessingItem().deserialize(json["processing"]) : null,
storage: json.containsKey("storage") ? StorageItem().deserialize(json["storage"]) : null,
datacenter: json.containsKey("datacenter") ? DataCenterItem().deserialize(json["datacenter"]) : null,
workflow: json.containsKey("workflow") ? WorkflowItem().deserialize(json["workflow"]) : null,
);
}
@override Map<String, dynamic> serialize() {
return {
"id": id,
"width": width,
"height": height,
"data": data?.serialize(),
"processing": processing?.serialize(),
"storage": storage?.serialize(),
"datacenter": datacenter?.serialize(),
"workflow": workflow?.serialize(),
"position": position?.serialize(),
};
}
}
class Position extends SerializerDeserializer<Position> {
String? id;
double? x;
double? y;
Position({
this.id,
this.x,
this.y,
});
@override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Position(); }
return Position(
id: json.containsKey("id") ? json["id"] : null,
x: json.containsKey("x") ? double.parse(json["x"].toString()) : null,
y: json.containsKey("y") ? double.parse(json["y"].toString()) : null,
);
}
@override Map<String, dynamic> serialize() => {
"id": id,
"x": x,
"y": y,
};
}

View File

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

View File

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

View File

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

View File

@ -1,7 +1,11 @@
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import 'package:go_router/go_router.dart';
import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart';
import 'package:oc_front/models/workflow.dart';
import 'package:oc_front/pages/abstract_page.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:oc_front/widgets/sheduler_items/schedule.dart';
class SchedulerFactory implements AbstractFactory {
static GlobalKey<SchedulerPageWidgetState> key = GlobalKey<SchedulerPageWidgetState>();
@ -11,18 +15,169 @@ class SchedulerFactory implements AbstractFactory {
}
class SchedulerPageWidget extends StatefulWidget {
bool isList = true;
DateTime start = DateTime.now();
DateTime end = DateTime.now().add(const Duration(days: 180));
final WorkflowExecutionService _service = WorkflowExecutionService();
SchedulerPageWidget(): super(key: SchedulerFactory.key);
@override SchedulerPageWidgetState createState() => SchedulerPageWidgetState();
static void search(BuildContext context) { }
static Widget factory() { return SchedulerPageWidget(); }
}
class SchedulerPageWidgetState extends State<SchedulerPageWidget> {
List<Color> colors = [Colors.blue, Colors.orange, Colors.red, Colors.green];
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"];
@override Widget build(BuildContext context) {
return TableCalendar(
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),
focusedDay: DateTime.now(),
);
return FutureBuilder(
future: widget._service.search(context, [
"${widget.start.year}-${widget.start.month > 9 ? widget.start.month : "0${widget.start.month}"}-${widget.start.day > 9 ? widget.start.day : "0${widget.start.day}"}",
"${widget.end.year}-${widget.end.month > 9 ? widget.end.month : "0${widget.end.month}"}-${widget.end.day > 9 ? widget.end.day : "0${widget.end.day}"}"], {}),
builder: (ctx, as) {
Map<String, List<WorkflowExecution>> data = {};
if (as.hasData && as.data!.data != null) {
for (var element in as.data!.data!.executions) {
if (element.executionData == null) { continue; }
DateTime dateTime = DateTime.parse(element.executionData!);
DateTime date = DateTime(dateTime.year, dateTime.month, dateTime.day);
var str = "${date.toIso8601String()}Z";
if (data[str] == null) { data[str] = []; }
data[str]!.add(element);
data[str]!.sort((a, b) => DateTime.parse(a.executionData!).compareTo(DateTime.parse(b.executionData!)));
}
}
GlobalKey<ScheduleWidgetState> k = GlobalKey<ScheduleWidgetState>();
return Column( children: [
Container( color: const Color.fromRGBO(38, 166, 154, 1),
height: 50, width: MediaQuery.of(context).size.width,
child: Padding(padding: const EdgeInsets.symmetric(horizontal: 50),
child: Row( children: [
Padding(padding: const EdgeInsets.only(right: 30),
child: Tooltip( message: widget.isList ? "calendar view" : "list view",
child: InkWell( child: Icon( widget.isList ? Icons.calendar_month : Icons.list, color: Colors.white
, size: 25 ),
onTap: () {
widget.isList = !widget.isList;
k.currentState?.setState(() { k.currentState?.widget.isList = widget.isList; });
})
),
),
Container(padding: const EdgeInsets.only(left: 20),
width: MediaQuery.of(context).size.width / 5,
height: 30,
child: DateTimeField(
validator: (value) {
return null;
},
resetIcon: const Icon(Icons.close, size: 15),
onShowPicker: (context, currentValue) async {
var date = await showDatePicker(
builder: (BuildContext context, Widget? child) {
Widget w = Theme(
data: ThemeData(
cardTheme: CardTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))),
dialogTheme: DialogTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))),
colorScheme: ColorScheme.light(
background: Colors.grey.shade300,
tertiary: Colors.grey,
secondary: Colors.grey,
primary: Colors.black),
),
child: child ?? Container(),
);
return w;
},
context: context,
firstDate: DateTime(1900),
initialDate: widget.start,
lastDate: DateTime(2100)
);
return date;
},
format: intl.DateFormat('y-M-dd hh:mm:ss'),
initialValue: widget.start,
onChanged: (value) {
if (value == null) { return; }
setState(() { widget.start = value; });
},
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
fillColor: Colors.white,
floatingLabelBehavior: FloatingLabelBehavior.always,
filled: true,
alignLabelWithHint: false,
hintText: "enter start date...",
labelText: "",
errorStyle: TextStyle(fontSize: 0),
hintStyle: TextStyle(fontSize: 10),
labelStyle: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500),
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)),
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
)
),
Container(padding: const EdgeInsets.only(left: 20),
child: const Text("TO", style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w500))),
Container( padding: const EdgeInsets.only(left: 20),
width: MediaQuery.of(context).size.width / 5,
height: 30,
child: DateTimeField(
validator: (value) {
return null;
},
resetIcon: const Icon(Icons.close, size: 15),
onShowPicker: (context, currentValue) async {
var date = await showDatePicker(
builder: (BuildContext context, Widget? child) {
Widget w = Theme(
data: ThemeData(
cardTheme: CardTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))),
dialogTheme: DialogTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))),
colorScheme: ColorScheme.light(
background: Colors.grey.shade300,
tertiary: Colors.grey,
secondary: Colors.grey,
primary: Colors.black),
),
child: child ?? Container(),
);
return w;
},
context: context,
firstDate: DateTime(1900),
initialDate: widget.end,
lastDate: DateTime(2100)
);
return date;
},
format: intl.DateFormat('y-M-dd hh:mm:ss'),
initialValue: widget.end,
onChanged: (value) {
if (value == null) { return; }
setState(() { widget.start = value; });
},
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
fillColor: Colors.white,
floatingLabelBehavior: FloatingLabelBehavior.always,
filled: true,
alignLabelWithHint: false,
hintText: "enter end date...",
labelText: "",
errorStyle: TextStyle(fontSize: 0),
hintStyle: TextStyle(fontSize: 10),
labelStyle: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500),
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)),
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
)
)
]))
),
ScheduleWidget( key: k, data: data, start: widget.start, end : widget.end, isList: widget.isList )
]);
});
}
}

View File

@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:go_router/go_router.dart';
@ -8,10 +6,16 @@ import 'package:oc_front/core/sections/header/header.dart';
import 'package:oc_front/core/services/specialized_services/workflow_service.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/search.dart';
import 'package:oc_front/models/workflow.dart';
import 'package:oc_front/pages/abstract_page.dart';
import 'package:oc_front/widgets/dialog/new_box.dart';
import 'package:oc_front/widgets/forms/proxy_forms.dart';
import 'package:oc_front/widgets/forms/scheduler_forms.dart';
import 'package:oc_front/widgets/items/item_row.dart';
Dashboard dash = Dashboard(name: "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}");
import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart';
Dashboard dash = Dashboard(
name: "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}");
class WorkflowFactory implements AbstractFactory {
static GlobalKey<WorkflowPageWidgetState> key = GlobalKey<WorkflowPageWidgetState>();
@override bool searchFill() { return false; }
@ -29,8 +33,10 @@ class WorkflowPageWidgetState extends State<WorkflowPageWidget> {
final WorflowService _service = WorflowService();
Widget itemBuild(Object item) {
var e = item as AbstractItem;
return e.logo != null ? Image.memory(base64Decode(e.logo ?? ""), fit: BoxFit.fill)
: Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', fit: BoxFit.fill);
return Tooltip( message: item.name ?? "",
child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill)
: Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp',
fit: BoxFit.fill));
}
Widget itemTooltipBuild(Object item) {
var e = item as AbstractItem;
@ -39,30 +45,113 @@ final WorflowService _service = WorflowService();
List<DropdownMenuItem> getItems(Object? data) {
data = data as APIResponse<RawData>?;
if (data != null && data.data != null && data.data!.values.isNotEmpty) {
return (data.data!.values as List<dynamic>).map((dynamic value) {
return data.data!.values.map((dynamic value) {
return DropdownMenuItem<String>(
value: value.toString(),
child: Text(value.toString()),
value: "${value["id"] ?? ""}~${value["name"] ?? ""}",
child: Text(value["name"]?.toString() ?? ""),
);
}).toList();
}
return [];
}
List<Widget> getForms(FlowData? obj) {
return obj == null ? [] : [
ProxyFormsWidget(item: obj as AbstractItem),
];
}
List<Widget> getDashInfoForms() {
return [
SchedulerFormsWidget(item: dash),
];
}
Future<void> loadDash(String selected) async {
if (selected.split("~").length > 1) {
dash.name = selected.split("~")[1];
dash.id = selected.split("~")[0];
} else {
dash.name = selected;
}
await _service.get(context, dash.id ?? "").then((value) {
if (value.data != null) {
dash.deserialize(value.data!.toDashboard());
}
});
}
Future<void> saveDash(String? id) async {
if (id == null || !dash.isOpened) { return; }
var datas = WorkspaceLocal.byTopic("data", true).where(
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
var dataCenter = WorkspaceLocal.byTopic("datacenter", true).where(
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
var storage = WorkspaceLocal.byTopic("storage", true).where(
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
var computing = WorkspaceLocal.byTopic("processing", true).where(
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
var workflows = WorkspaceLocal.byTopic("workflows", true).where(
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
var updateW = Workflow(
name: dash.name,
graph: Graph(),
data: datas.map((e) => e.id).toSet().toList(),
datacenter: dataCenter.map((e) => e.id).toSet().toList(),
storage: storage.map((e) => e.id).toSet().toList(),
processing: computing.map((e) => e.id).toSet().toList(),
workflows: workflows.map((e) => e.id).toSet().toList(),
);
updateW.fromDashboard(dash.serialize());
for (var item in (updateW.graph?.items.values ?? [] as List<GraphItem>)) {
if (item.position == null) { continue; }
item.position?.x = (item.position?.x ?? 0) + 52.5;
item.position?.y = (item.position?.y ?? 0) + 52.5;
}
print(dash.getZoomFactor());
updateW.graph?.zoom = dash.getZoomFactor();
await _service.put(context, id, updateW.serialize(), {});
}
FlowData? transformToData(Map<String, dynamic> data) {
var d = WorkspaceLocal.getItem(data["id"] ?? "", true);
if (d == null) { return null; }
d.model = ResourceModel().deserialize(data["resource_model"]);
if (d.topic == "data") { return d as DataItem; }
if (d.topic == "datacenter") { return d as DataCenterItem; }
if (d.topic == "storage") { return d as StorageItem; }
if (d.topic == "processing") { return d as ProcessingItem; }
if (d.topic == "workflows") { return d as WorkflowItem; }
return null;
}
Widget menuExtension() {
var quart = MediaQuery.of(context).size.width / 6;
return MenuWorkspaceWidget(simpliest: true, width: quart > 80 ? quart : 80,
onWorkspaceChange: () { dash.selectedLeftMenuKey.currentState?.setState(() { }); });
}
Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) {
return NewBoxWidget<RawData>(service: _service, dash: dash,
return NewBoxWidget<Workflow>(service: _service, dash: dash,
getItems: getItems);
}
@override Widget build(BuildContext context) {
dash.load = loadDash;
dash.save = saveDash;
dash.transformToData = transformToData;
dash.infoItemWidget = getForms;
dash.infoWidget = getDashInfoForms;
var quart = MediaQuery.of(context).size.width / 6;
dash.defaultName = "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}";
return FlowChart<AbstractItem>(
onDashboardAlertOpened: onDashboardAlertOpened,
dashboard: dash,
itemWidget: itemBuild,
categories: const ["computing", "data", "datacenter", "storage"],
draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat).toList(),
categories: const ["processing", "data", "datacenter", "storage", "workflows"],
draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, true).toList(),
itemWidgetTooltip: itemTooltipBuild,
innerMenuWidth: quart > 80 ? quart : 80,
menuExtension: menuExtension,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - HeaderConstants.height,
onNewConnection: (p1, p2) { },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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