diff --git a/.flutter-plugins b/.flutter-plugins index 7cbabd5..9bdf805 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,19 +1,16 @@ # This is a generated file; do not edit or check into version control. -desktop_window=/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/ -device_info_plus=/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/ +desktop_window=/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.1/ +device_info_plus=/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/ irondash_engine_context=/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/ -path_provider=/home/mr/.pub-cache/hosted/pub.dev/path_provider-2.1.3/ +path_provider=/home/mr/.pub-cache/hosted/pub.dev/path_provider-2.1.4/ path_provider_android=/home/mr/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/ path_provider_foundation=/home/mr/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/ path_provider_linux=/home/mr/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/home/mr/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ +path_provider_windows=/home/mr/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/ shared_preferences=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ shared_preferences_android=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/ -shared_preferences_foundation=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/ -shared_preferences_linux=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/ -shared_preferences_web=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ -shared_preferences_windows=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ -super_native_extensions=/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/ -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/ +shared_preferences_foundation=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/ +shared_preferences_linux=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/ +shared_preferences_web=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.1/ +shared_preferences_windows=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/ +super_native_extensions=/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index a2e3a87..5d5679a 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/","native_build":true,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]},{"name":"webview_flutter_wkwebview","path":"/home/mr/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-3.14.0/","native_build":true,"dependencies":[]}],"android":[{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/","native_build":true,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/","native_build":true,"dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]},{"name":"webview_flutter_android","path":"/home/mr/.pub-cache/hosted/pub.dev/webview_flutter_android-3.16.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"desktop_window","path":"/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/","native_build":true,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"linux":[{"name":"desktop_window","path":"/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/","native_build":false,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"windows":[{"name":"desktop_window","path":"/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/","native_build":false,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"web":[{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.0/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/","dependencies":["device_info_plus"]}]},"dependencyGraph":[{"name":"desktop_window","dependencies":[]},{"name":"device_info_plus","dependencies":[]},{"name":"irondash_engine_context","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"super_native_extensions","dependencies":["irondash_engine_context","device_info_plus"]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2024-08-07 17:05:28.926423","version":"3.19.6"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"android":[{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/","native_build":true,"dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"macos":[{"name":"desktop_window","path":"/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.1/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"linux":[{"name":"desktop_window","path":"/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.1/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":false,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"windows":[{"name":"desktop_window","path":"/home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.1/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":false,"dependencies":[]},{"name":"irondash_engine_context","path":"/home/mr/.pub-cache/hosted/pub.dev/irondash_engine_context-0.5.4/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/mr/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/","native_build":true,"dependencies":["irondash_engine_context","device_info_plus"]}],"web":[{"name":"device_info_plus","path":"/home/mr/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.1/","dependencies":[]},{"name":"super_native_extensions","path":"/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.19/","dependencies":["device_info_plus"]}]},"dependencyGraph":[{"name":"desktop_window","dependencies":[]},{"name":"device_info_plus","dependencies":[]},{"name":"irondash_engine_context","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"super_native_extensions","dependencies":["irondash_engine_context","device_info_plus"]}],"date_created":"2024-11-08 13:55:50.054561","version":"3.24.3","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4314849..59f33ba 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ .buildlog/ .history .svn/ +build/ migrate_working_dir/ # IntelliJ related diff --git a/Dockerfile b/Dockerfile index 6f902f1..2573f7e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,9 +10,8 @@ ARG WORKFLOW_HOST="http://localhost:8088/oc" ARG ITEM_HOST="http://localhost:8087/oc" ARG SCHEDULER_HOST="http://localhost:8090/oc" ARG LOGS_HOST="http://localhost:3100" -ARG PEER_HOST="http://localhost:8091/oc" -ARG COLLABORATIVE_AREA_HOST="http://localhost:8094/oc" - +ARG PEER_HOST="http://localhost:8093/oc" +ARG COLLABORATIVE_AREA_HOST="http://localhost:8091/oc" # define variables ARG FLUTTER_SDK=/usr/local/flutter ARG FLUTTER_VERSION=3.19.6 @@ -47,7 +46,7 @@ RUN flutter build web \ --dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST \ --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST \ --dart-define=LOGS_HOST=$LOGS_HOST \ - --dart-define=ITEM_HOST=$ITEM_HOST + --dart-define=ITEM_HOST=$ITEM_HOST \ # once heare the app will be compiled and ready to deploy # use nginx to deploy diff --git a/README.md b/README.md index 9d1a2d3..680086d 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,7 @@ At the root of the project : - `docker build . -t oc-front` if localisation services change : `docker build -t oc-front --build-arg WORKSPACE_HOST= --build-arg WORKFLOW_HOST= --build-arg SEARCH_HOST= --build-arg ITEM_HOST= .` - - `docker-compose up -d --build --force-recreate` \ No newline at end of file + - `docker-compose up -d --build --force-recreate` + +## HELP +sudo apt install libwebkit2gtk-4.0-dev \ No newline at end of file diff --git a/lib/core/models/shared_workspace_local.dart b/lib/core/models/shared_workspace_local.dart index a0186d4..e2e898e 100644 --- a/lib/core/models/shared_workspace_local.dart +++ b/lib/core/models/shared_workspace_local.dart @@ -13,35 +13,35 @@ class WorkSpaceItem { WorkSpaceItem({this.id, this.name}); } -class SharedWorkspaceLocal { +class CollaborativeAreaLocal { static String? current; - static Map workspaces = {}; + static Map workspaces = {}; static final SharedService _service = SharedService(); static void init(BuildContext context, bool changeCurrent) { - _service.all(context).then((value) { + _service.all(context).then((value) { if (value.data != null && value.data!.values.isNotEmpty ) { var vals = value.data!.values; for (var element in vals) { - var ws = SharedWorkspace().deserialize(element); + var ws = CollaborativeArea().deserialize(element); if (ws.id == null) { continue; } workspaces[ws.id!] = ws; } } - }); + }).catchError((e) => print(e)); } - static SharedWorkspace? getSharedWorkspace(String id) { + static CollaborativeArea? getCollaborativeArea(String id) { return workspaces[id]; } - static Future deleteSharedWorkspace(String id) async { + static Future deleteCollaborativeArea(String id) async { if (workspaces.containsKey(id) && workspaces.length == 1) { return; } workspaces.remove(id); await _service.delete(null, id, {}); } - static Future createSharedWorkspace(String name, BuildContext? context) async { + static Future createCollaborativeArea(String name, BuildContext? context) async { Workspace n = Workspace(name: name); await _service.post(context, n.serialize(), {}).then((value) { if (value.data != null) { @@ -67,7 +67,7 @@ class SharedWorkspaceLocal { WorkflowFactory.key.currentState?.setState(() {}); } - static List getSharedWorkspacesIDS() { + static List getCollaborativeAreasIDS() { List res = []; for (var element in workspaces.entries) { res.add(WorkSpaceItem(id: element.key, name: element.value.name)); diff --git a/lib/core/models/workspace_local.dart b/lib/core/models/workspace_local.dart index 7c4b65f..8a57959 100644 --- a/lib/core/models/workspace_local.dart +++ b/lib/core/models/workspace_local.dart @@ -1,6 +1,7 @@ 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/core/sections/header/header.dart'; import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/models/workspace.dart'; @@ -21,28 +22,28 @@ class WorkspaceLocal { static final WorkspaceService _service = WorkspaceService(); static List items = []; - static void init(BuildContext context, bool changeCurrent) { - _service.all(context).then((value) { - if (value.data != null && value.data!.values.isNotEmpty ) { - var vals = value.data!.values; - for (var element in vals) { - var ws = Workspace().deserialize(element); - if (ws.id == null) { continue; } - workspaces[ws.id!] = ws; - if (current == null) { - current ??= ws.id; - workspaces[current!] = ws; - _service.put(context, ws.id!, { "active" : true }, {}); - } - if (ws.active == true && changeCurrent) { - current = ws.id; - } - fill(); + static Future init(BuildContext context, bool changeCurrent) async { + var value = await _service.all(context); + if (value.data != null && value.data!.values.isNotEmpty ) { + var vals = value.data!.values; + for (var element in vals) { + var ws = Workspace().deserialize(element); + if (ws.id == null) { continue; } + workspaces[ws.id!] = ws; + if (current == null) { + current ??= ws.id; + workspaces[current!] = ws; + _service.put(context, ws.id!, { "active" : true }, {}); } - } else { - WorkspaceLocal.createWorkspace("main", null); + if (ws.active == true && changeCurrent) { + current = ws.id; + } + fill(); + HeaderConstants.headerKey.currentState?.setState(() {}); } - }); + } else { + await WorkspaceLocal.createWorkspace("default workspace", null); + } } static void fill() { @@ -55,7 +56,7 @@ class WorkspaceLocal { for (var element in workspaces[current]!.processings) { if (WorkspaceLocal.hasItemByID(element.getID())) { continue; } items.add(element); } - for (var element in workspaces[current]!.datacenters) { + for (var element in workspaces[current]!.computes) { if (WorkspaceLocal.hasItemByID(element.getID())) { continue; } items.add(element); } @@ -74,6 +75,13 @@ class WorkspaceLocal { return workspaces[current]; } + static bool hasWorkspace(String workspaceName) { + for (var element in workspaces.values) { + if (element.name == workspaceName) { return true; } + } + return false; + } + static Future deleteWorkspace(String id) async { if (workspaces.containsKey(id) && workspaces.length == 1) { return; } workspaces.remove(id); @@ -89,28 +97,36 @@ class WorkspaceLocal { current = value.data!.id; fill(); endDrawerKey.currentState?.setState(() {}); - CatalogFactory.key.currentState?.setState(() {}); - CatalogItemFactory.key.currentState?.setState(() {}); - WorkflowFactory.key.currentState?.setState(() {}); + CatalogFactory.key.currentState?.setState(() {}); + CatalogItemFactory.key.currentState?.setState(() {}); + WorkflowFactory.key.currentState?.setState(() {}); + HeaderConstants.headerKey.currentState?.setState(() {}); } }); } static void changeWorkspaceByName(String name) { - var id = workspaces.entries.firstWhere((element) => element.value.name == "${name}_workspace").key; - changeWorkspace(id); + try { + var id = workspaces.entries.firstWhere((element) => element.value.name == "${name}_workspace").key; + changeWorkspace(id); + } catch (e) {} } static void changeWorkspace(String id) { _service.put(null, id, { "active" : true }, {}); current = id; fill(); + HeaderConstants.headerKey.currentState?.setState(() {}); endDrawerKey.currentState?.setState(() {}); CatalogFactory.key.currentState?.setState(() {}); CatalogItemFactory.key.currentState?.setState(() {}); WorkflowFactory.key.currentState?.setState(() {}); } + static String getWorkspaceName(String id) { + return workspaces[id]?.name ?? ""; + } + static List getWorkspacesIDS() { List res = []; for (var element in workspaces.entries) { @@ -131,7 +147,7 @@ class WorkspaceLocal { List> d = []; var w = workspaces[id]!; 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.computes.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.processings.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.storages.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.workflows.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; @@ -143,7 +159,7 @@ class WorkspaceLocal { List> 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.computes.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.processings.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.storages.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.workflows.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; @@ -158,7 +174,7 @@ class WorkspaceLocal { List> 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.computes.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.processings.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.storages.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; d = [ ...d, ...w.workflows.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; @@ -174,7 +190,7 @@ class WorkspaceLocal { items.add(item); 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 == "compute") { workspaces[current]!.computes.add(item as ComputeItem); } if (item.topic == "storage") { workspaces[current]!.storages.add(item as StorageItem); } if (item.topic == "workflow") { workspaces[current]!.workflows.add(item as WorkflowItem); } try { _service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {}); @@ -186,7 +202,7 @@ class WorkspaceLocal { items = items.where((element) => element.name != item.name).toList(); 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 == "compute") { workspaces[current]!.computes.removeWhere( (e) => e.id == item.id); } if (item.topic == "storage") { workspaces[current]!.storages.removeWhere( (e) => e.id == item.id); } if (item.topic == "workflow") { workspaces[current]!.workflows.removeWhere( (e) => e.id == item.id); } try { _service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {}); diff --git a/lib/core/sections/end_drawer.dart b/lib/core/sections/end_drawer.dart index 6449c70..e9ec330 100644 --- a/lib/core/sections/end_drawer.dart +++ b/lib/core/sections/end_drawer.dart @@ -1,14 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:oc_front/core/models/shared_workspace_local.dart'; -import 'package:oc_front/core/services/specialized_services/shared_service.dart'; -import 'package:oc_front/core/services/specialized_services/workspace_service.dart'; -import 'package:oc_front/models/response.dart'; +import 'package:oc_front/main.dart'; 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/pages/shared.dart'; +import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; import 'package:oc_front/widgets/items/item_row.dart'; import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; +import 'package:oc_front/core/services/specialized_services/workspace_service.dart'; GlobalKey endDrawerKey = GlobalKey(); class EndDrawerWidget extends StatefulWidget { @@ -24,12 +23,12 @@ class EndDrawerWidgetState extends State { Container( color: Colors.white, width: 400, - height: MediaQuery.of(context).size.height, + height: getHeight(context), child: Column( children: [ Container( width: 400, height: 50, - decoration: const BoxDecoration(color: Color.fromRGBO(38, 166, 154, 1)), + decoration: BoxDecoration(color: lightColor ), child: const Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -41,53 +40,61 @@ class EndDrawerWidgetState extends State { ), ShallowDropdownInputWidget( current: WorkspaceLocal.current, - filled: Colors.grey.shade200, + filled: Colors.white, width: 400, all: () async => WorkspaceLocal.getWorkspacesShallow(), canRemove: (p0) => p0 != null, remove: (p0) async { await WorkspaceService().delete(context, p0, {}).then( (e) => WorkspaceLocal.deleteWorkspace(p0)); }, - type: SharedWorkspaceType.workspace, + type: CollaborativeAreaType.workspace, change: (String? change) { WorkspaceLocal.changeWorkspace(change.toString()); } ), + Container( + width: 400, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + border: Border(bottom: BorderSide(color: midColor), top: BorderSide(color: midColor)), + ), + child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + Padding(padding: EdgeInsets.only(right: 5), child: Icon(Icons.share, size: 12, color: Colors.grey)), + Text( (WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared) == null ? + "actually not shared" : "share with ${WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared!}", + style: TextStyle( fontSize: 14, color: Colors.grey ),), + ]), + ), Column( children: [ - 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)))) - : Container( height: MediaQuery.of(context).size.height - 100, child: SingleChildScrollView( + itemRows.isEmpty ? Container( height: getHeight(context) - 140, + color: Colors.white, + child: Center(child: Text("WORKSPACE IS EMPTY", + style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: midColor)))) + : Container( height: getHeight(context) - 140, child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Column( children: [ ...itemRows, Container(height: 50)]) )), ]) ]) ), - itemRows.isEmpty ? Container() : Positioned( bottom: 0, left: 0, - child: ShallowDropdownInputWidget( - type: SharedWorkspaceType.workspace, - all: () async => SharedWorkspaceLocal.workspaces.values.map( - (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), - current: WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared, - width: 400, - filled: Colors.grey.shade300, - hintColor: Colors.grey, - color: Colors.black, - canLoad: (String? change) => SharedWorkspaceLocal.workspaces[change] == null - || !SharedWorkspaceLocal.workspaces[change]!.workspaces.map( (e) => e.id ).contains(WorkspaceLocal.current), - canRemove: (String? change) => SharedWorkspaceLocal.workspaces[change] == null - || SharedWorkspaceLocal.workspaces[change]!.workspaces.map( (e) => e.id ).contains(WorkspaceLocal.current), - load: (String val) async { - await SharedService().addWorkspace(context, val, WorkspaceLocal.current ?? ""); - SharedWorkspaceLocal.init(context, false); - }, - remove: (String val) async { - await SharedService().removeWorkspace(context, val, WorkspaceLocal.current ?? ""); - SharedWorkspaceLocal.init(context, false); - }) - ) + Positioned( bottom: 0, left: 0, + child: Tooltip( message: "create workspace", child: ShallowTextInputWidget( + width: 400, + tooltipLoad: "create workspace", + iconLoad: Icons.create_new_folder_sharp, + type: CollaborativeAreaType.workspace, + color: Colors.white, + filled: midColor, + hint: "enter workspace name", + hintColor: Colors.grey, + canLoad: (String? remove) => remove != null, + load: (Map add) async { + if (add["name"] == null) { return; } + WorkspaceLocal.createWorkspace(add["name"], context); + }, + ), + )) ] ); } diff --git a/lib/core/sections/header/default.dart b/lib/core/sections/header/default.dart new file mode 100644 index 0000000..e20146a --- /dev/null +++ b/lib/core/sections/header/default.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/core/services/perms_service.dart'; +import 'package:oc_front/core/services/router.dart'; +import 'package:oc_front/main.dart'; +import 'package:oc_front/pages/shared.dart'; +import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; + +class DefaultWidget extends StatefulWidget{ + const DefaultWidget (): super(key: null); + @override DefaultWidgetState createState() => DefaultWidgetState(); +} +class DefaultWidgetState extends State { + + @override Widget build(BuildContext context) { + return Container( + width: getMainWidth(context), + height: getHeight(context) - 50, + color: midColor, + padding: EdgeInsets.only(top: 50), + child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: getMainHeight(context) < 600 ? MainAxisAlignment.center : MainAxisAlignment.start, + children: [ getMainHeight(context) < 600 ? Container() : Container( + margin: EdgeInsets.only(left: 40), + child: SvgPicture.asset("assets/images/logo.svg", width: 300, height: (getMainHeight(context) / (1.8) ), semanticsLabel: 'OpenCloud Logo') + ), + ShallowTextInputWidget( + alignment: MainAxisAlignment.center, + width: getMainWidth(context) / 1.5, + type: CollaborativeAreaType.workspace, + hint: "search in resources...", + iconLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? Icons.search : null, + iconRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? Icons.screen_search_desktop_outlined : null, + tooltipLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? "search" : null, + tooltipRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? "distributed search" : null, + canLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String? str) => str != null && str.isNotEmpty : null, + canRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String? str) => str != null && str.isNotEmpty : null, + change: (value) => SearchConstants.set(value), + loadStr: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String val) async { + AppRouter.currentRoute.factory.search(context, false); + } : null, + remove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String val) async { + AppRouter.currentRoute.factory.search(context, true); + } : null, + ) + ]) + ); + } +} \ No newline at end of file diff --git a/lib/core/sections/header/header.dart b/lib/core/sections/header/header.dart index 64f93c2..d389c14 100644 --- a/lib/core/sections/header/header.dart +++ b/lib/core/sections/header/header.dart @@ -1,11 +1,27 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/core/models/workspace_local.dart'; +import 'package:oc_front/core/sections/header/default.dart'; import 'package:oc_front/core/sections/header/menu.dart'; -import 'package:oc_front/core/sections/header/search.dart'; +import 'package:oc_front/core/services/perms_service.dart'; import 'package:oc_front/core/services/router.dart'; -import 'package:oc_front/widgets/menus/clipper_menu.dart'; +import 'package:oc_front/main.dart'; +import 'package:oc_front/pages/shared.dart'; +import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; +import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; + +class SearchConstants { + static final Map _searchHost = {}; + static String? get() { return _searchHost[AppRouter.currentRoute.route]; } + static void set(String? search) { _searchHost[AppRouter.currentRoute.route] = search; } + static void remove() { _searchHost.remove(AppRouter.currentRoute.route); } + static void clear() { _searchHost.clear(); } +} class HeaderConstants { + static GlobalKey headerKey = GlobalKey(); static final List noHeader = [ + AppRouter.scheduler, + AppRouter.shared, AppRouter.workflowItem, AppRouter.workflowIDItem, ]; @@ -14,6 +30,11 @@ class HeaderConstants { static String? title; static String? description; + static getKey() { + headerKey = GlobalKey(); + return headerKey; + } + static setTitle(String? v) { title = v; HeaderConstants.headerWidget?.setState(() {}); @@ -36,11 +57,65 @@ class HeaderWidget extends StatefulWidget { class HeaderWidgetState extends State { @override Widget build(BuildContext context) { HeaderConstants.headerWidget = this; - headerMenuKey.currentState?.closeMenu(); - HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) ? 50 : 200; + if (HeaderConstants.isNoHeader(AppRouter.currentRoute.route)) { + return Container(); + } + if (AppRouter.currentRoute.factory.searchFill()) { + return DefaultWidget(); + } + HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) || AppRouter.currentRoute.factory.searchFill() ? 50 : 100; return Column( children: [ - const HeaderMenuWidget(), - HeaderConstants.isNoHeader(AppRouter.currentRoute.route) ? Container() : SearchWidget() + AppRouter.currentRoute.factory.searchFill() ? Container() : Container( + height: 50, width: getMainWidth(context), + decoration: BoxDecoration( + color: midColor, + border: Border(bottom: BorderSide(color: Colors.white, width: 1),) + ), + child: Row(crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ShallowTextInputWidget( + filled: midColor, + width: getMainWidth(context) - 451, + type: CollaborativeAreaType.workspace, + hint: "search in resources...", + iconLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? Icons.search : null, + iconRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? Icons.screen_search_desktop_outlined : null, + tooltipLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? "search" : null, + tooltipRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? "distributed search" : null, + canLoad: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String? str) => str != null && str.isNotEmpty : null, + canRemove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String? str) => str != null && str.isNotEmpty : null, + change: (value) => SearchConstants.set(value), + loadStr: PermsService.getPerm(Perms.SEARCH_INTERNAL) ? (String val) async { + AppRouter.currentRoute.factory.search(context, false); + } : null, + remove: PermsService.getPerm(Perms.SEARCH_EXTERNAL) ? (String val) async { + AppRouter.currentRoute.factory.search(context, true); + } : null, + ), + Container( padding: EdgeInsets.only(left: 50), + decoration: BoxDecoration( border: Border( left: BorderSide( color: Colors.white ))), + child: ShallowDropdownInputWidget( + prefixIcon: Padding( padding: EdgeInsets.only(right: 10), child: Icon(Icons.shopping_cart, color: Colors.grey)), + current: WorkspaceLocal.current, + width: 350, + all: () async => WorkspaceLocal.getWorkspacesShallow(), + type: CollaborativeAreaType.workspace, + change: (String? change) { + WorkspaceLocal.changeWorkspace(change.toString()); + }, + canLoad: (p0) => true, + load: (p0) async { + scaffoldKey.currentState?.openEndDrawer(); + }, + tooltipLoad: "open workspace manager", + iconLoad: Icons.remove_red_eye, + color: Colors.black, + filled: midColor, + hintColor: Colors.grey, + )) + ]) + ), ],); } } diff --git a/lib/core/sections/header/menu.dart b/lib/core/sections/header/menu.dart index c2d7483..7c1711f 100644 --- a/lib/core/sections/header/menu.dart +++ b/lib/core/sections/header/menu.dart @@ -1,51 +1,54 @@ +import 'package:flutter_svg/svg.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/core/services/auth.service.dart'; +import 'package:oc_front/core/services/router.dart'; import 'package:oc_front/main.dart'; import 'package:flutter/material.dart'; -import 'package:oc_front/widgets/menus/clipper_menu.dart'; -import 'package:oc_front/widgets/dialog/login.dart'; class HeaderMenuWidget extends StatefulWidget{ - const HeaderMenuWidget ({ super.key }); + HeaderMenuWidget (): super(key: HeaderConstants.getKey()); @override HeaderMenuWidgetState createState() => HeaderMenuWidgetState(); } class HeaderMenuWidgetState extends State { + @override Widget build(BuildContext context) { return Container( - width: MediaQuery.of(context).size.width, + width: getWidth(context), height: 50, decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey.shade300)) + color: Colors.white, + border: Border(bottom: BorderSide(color: midColor)) ), - child: Padding(padding: const EdgeInsets.only(top: 5, bottom: 5, left: 50, right: 50), - child: Stack(children: [ - Row(crossAxisAlignment: CrossAxisAlignment.stretch, + child: Stack(children: [ + AppRouter.currentRoute.factory.searchFill() ? Container() : Positioned( top: 0, left: 30, child: InkWell( onTap: () { + AppRouter.currentRoute = AppRouter.zones.first; + AppRouter.currentRoute.factory.clear(); + AppRouter.zones.first.go(context, {}); + }, + child: SvgPicture.asset("assets/images/icon.svg", width: 70, height: 70, semanticsLabel: 'OpenCloud Logo'))), + Padding( padding: const EdgeInsets.only(left: 50), + child: Row(crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.end, children: [ - Tooltip( message: "workspace/cart", child: Padding(padding: const EdgeInsets.only(left: 10), - child: IconButton( - icon: const Icon(Icons.shopping_cart_outlined), - onPressed: () { - headerMenuKey.currentState?.closeMenu(); - scaffoldKey.currentState?.openEndDrawer(); - }, - ) + Center(child: Text("hello \"${AuthService.getUsername() ?? ""}\"", style: const TextStyle(color: Colors.grey, fontSize: 15))), + Padding(padding: const EdgeInsets.only(top: 5, bottom: 5, right: 50, left: 20), + child: Row(crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Tooltip( message: "logout", child: Padding(padding: const EdgeInsets.only(left: 10), + child: IconButton( + icon: const Icon(FontAwesomeIcons.powerOff), + onPressed: () async { + await AuthService.logout(); + mainKey?.currentState?.setState(() {}); + }, + ) )), - Tooltip( message: "login", child: Padding(padding: const EdgeInsets.only(left: 10), - child: IconButton( - icon: const Icon(Icons.login_outlined), - onPressed: () { showDialog(context: context, builder: (context) => - LoginWidget()); }, - ) - )), - Tooltip( message: "navigation", child: Padding(padding: const EdgeInsets.only(left: 10), - child: ClipperMenuWidget( - borderRadius: BorderRadius.circular(4), - iconColor: Colors.white, - ) - )) ] - ) + )) ]) - ) + )]) ); } } \ No newline at end of file diff --git a/lib/core/sections/header/search.dart b/lib/core/sections/header/search.dart deleted file mode 100644 index 609e725..0000000 --- a/lib/core/sections/header/search.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:oc_front/core/sections/header/header.dart'; -import 'package:oc_front/core/services/router.dart'; -import 'package:oc_front/pages/shared.dart'; -import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; - -class SearchConstants { - static final Map _searchHost = {}; - static String? get() { return _searchHost[AppRouter.currentRoute.route]; } - static void set(String? search) { _searchHost[AppRouter.currentRoute.route] = search; } - static void remove() { _searchHost.remove(AppRouter.currentRoute.route); } - static void clear() { _searchHost.clear(); } -} - -GlobalKey searchWidgetKey = GlobalKey(); -class SearchWidget extends StatefulWidget { - SearchWidget (): super(key: GlobalKey()); - @override SearchWidgetState createState() => SearchWidgetState(); -} -class SearchWidgetState extends State { - @override Widget build(BuildContext context) { - searchWidgetKey = widget.key as GlobalKey; - List widgets = [ - ...(MediaQuery.of(context).size.width > 600 || AppRouter.currentRoute.factory.searchFill() - ? [InkWell( - mouseCursor: SystemMouseCursors.click, - onTap: () => AppRouter.zones.first.go(context, {}), - child: Container( - margin: EdgeInsets.only(top: 20, left: AppRouter.currentRoute.factory.searchFill() ? 40 : 0), - child: SvgPicture.asset( - width: 300, - height: AppRouter.currentRoute.factory.searchFill() ? - ((MediaQuery.of(context).size.height - 50) / 2) : 150, - "assets/images/logo.svg", - semanticsLabel: 'OpenCloud Logo' - ) - ) - )] : []), - AppRouter.currentRoute.description != null - || (AppRouter.currentRoute.route.contains("shared") && HeaderConstants.title != null) ? - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(HeaderConstants.title ?? AppRouter.currentRoute.description!, style: const TextStyle( - color: Color.fromRGBO(38, 166, 154, 1), - fontSize: 24, - fontWeight: FontWeight.w600 - )), - Row(children: [ - ...(HeaderConstants.description == null && (AppRouter.currentRoute.help == null || AppRouter.currentRoute.help!.isEmpty) ? [] - : [ const Padding( padding: EdgeInsets.only(right: 10), - child: Icon(Icons.help_outline, color: Colors.grey, size: 20)), - Text(HeaderConstants.description ?? AppRouter.currentRoute.help ?? "", style: const TextStyle( - color: Colors.grey, - fontSize: 14, - fontWeight: FontWeight.w400 - )) ]) - ],) - - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ ShallowTextInputWidget( - width: MediaQuery.of(context).size.width - 400 > 0 ? MediaQuery.of(context).size.width - 300 - 100 : 200, - type: SharedWorkspaceType.workspace, - hint: "search in resources...", - iconLoad: Icons.search, - iconRemove: Icons.screen_search_desktop_outlined, - tooltipLoad: "search", - tooltipRemove: "distributed search", - canLoad: (String? str) => str != null && str.isNotEmpty, - canRemove: (String? str) => str != null && str.isNotEmpty, - change: (value) => SearchConstants.set(value), - loadStr: (String val) async { - AppRouter.currentRoute.factory.search(context); - }, - remove: (String val) async { - AppRouter.currentRoute.factory.search(context); - }, - ) ]), - ]; - return Container( - width: MediaQuery.of(context).size.width, - height: AppRouter.currentRoute.factory.searchFill() ? (MediaQuery.of(context).size.height - 50) : 150, - color: Colors.grey.shade300, - child: AppRouter.currentRoute.factory.searchFill() ? Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: widgets) - : Row( mainAxisAlignment: MediaQuery.of(context).size.width < 600 - ? MainAxisAlignment.center : MainAxisAlignment.start, children: widgets) - ); - } -} \ No newline at end of file diff --git a/lib/core/sections/left_menu.dart b/lib/core/sections/left_menu.dart new file mode 100644 index 0000000..d3aea00 --- /dev/null +++ b/lib/core/sections/left_menu.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:oc_front/core/services/router.dart'; + +class LeftMenuWidget extends StatefulWidget { + const LeftMenuWidget({Key? key}): super(key: key); + @override LeftMenuWidgetState createState() => LeftMenuWidgetState(); +} + +class LeftMenuWidgetState extends State { + @override Widget build(BuildContext context) { + var routes = AppRouter.zones.where( (e) => e.label != null && e.icon != null).toList(); + List widgets = routes.map( (e) => Opacity( opacity: AppRouter.currentRoute.route == e.route ? 1 : .5, + child: Tooltip( message: e.label, child: SizedBox( width: 50, height: 50, child: InkWell( + onTap: () { e.go(context, {}); }, + child: Center( child: Icon(e.icon, color:Colors.white) ), + ), + )))).toList(); + return Column( children: widgets); + } +} \ No newline at end of file diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index b23daef..3d17296 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:alert_banner/exports.dart'; +import 'package:localstorage/localstorage.dart'; import 'package:oc_front/models/abstract.dart'; import 'package:oc_front/models/response.dart'; import 'package:oc_front/widgets/dialog/alert.dart'; @@ -11,16 +12,14 @@ import 'package:oc_front/core/services/html.dart' if (kIsWeb) 'dart:html' as htt class APIService { static bool forceRequest = false; static Map> cache = >{}; - static String auth = ""; Dio _dio = Dio( BaseOptions( baseUrl: const String.fromEnvironment('HOST', defaultValue: 'http://localhost:8080'), // you can keep this blank headers: { 'Content-Type': 'application/json; charset=UTF-8' }, ), - )..interceptors.add(LogInterceptor( requestHeader: true, ),); + )..interceptors.add(LogInterceptor( requestHeader: true, )); - APIService({ required String baseURL }) { - print("BASE URL " + baseURL); + APIService({ required String baseURL}) { _dio = Dio( BaseOptions( baseUrl: baseURL, // you can keep this blank @@ -52,7 +51,6 @@ class APIService { Future _mainDownload(String url, String method, bool isFilter, String? extend, String savePath, bool isWeb, BuildContext context) async { try { downloadProgressNotifier.value = 0; - // dio.options.headers["authorization"] = auth; if (isWeb) { _dio.get("$url${extend ?? ""}").then((value) { var url = http.Url.createObjectUrlFromBlob(http.Blob([value.data])); @@ -76,9 +74,9 @@ class APIService { BuildContext? context, Options? options) async { var err = ""; try { - _dio.options.headers["authorization"] = auth; + var type = localStorage.getItem('tokenType') ?? "bearer"; + _dio.options.headers["Authorization"] = "${type[0].toUpperCase() + type.substring(1)} ${localStorage.getItem('accessToken') ?? ""}"; _dio.interceptors.clear(); - print(url); var response = await _request(url, method, body, options); if (response.statusCode != null && response.statusCode! < 400) { if (method == "delete") { cache.remove(url); return APIResponse(); } @@ -112,9 +110,9 @@ class APIService { var err = ""; if (url != "") { try { - _dio.options.headers["authorization"] = auth; + var type = localStorage.getItem('tokenType') ?? "bearer"; + _dio.options.headers["Authorization"] = "${type[0].toUpperCase() + type.substring(1)} ${localStorage.getItem('accessToken') ?? ""}"; _dio.interceptors.clear(); - var response = await _request(url, method, body, null); if (response.statusCode != null && response.statusCode! < 400) { if (method == "delete") { cache.remove(url); return APIResponse(); } @@ -126,7 +124,6 @@ class APIService { } catch(e, s) { print(e); print(s); err = "${e.toString()} ${const String.fromEnvironment('HOST', defaultValue: 'http://localhost:8080')}"; } } else { err = "no url"; } - // if (err.contains("token") && err.contains("expired")) { AuthService().unAuthenticate(); } throw Exception(err); } diff --git a/lib/core/services/auth.service.dart b/lib/core/services/auth.service.dart new file mode 100644 index 0000000..c05cd09 --- /dev/null +++ b/lib/core/services/auth.service.dart @@ -0,0 +1,82 @@ + +import 'package:localstorage/localstorage.dart'; +import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/core/services/api_service.dart'; +import 'package:oc_front/models/response.dart'; +class AuthService { + static APIService service = APIService( + baseURL: const String.fromEnvironment('AUTH_HOST', defaultValue: 'http://localhost:8080/auth'), + ); + static Future init() async { + bool ok = await introspect().catchError( (e) => false ); + if (ok) { + var now = DateTime.now(); + var expires = DateTime.parse(localStorage.getItem('expiresIn') ?? DateTime.now().toIso8601String()); + var duration = expires.difference(now); + refresh(localStorage.getItem('accessToken') ?? "", localStorage.getItem('username') ?? "", duration); + } else { + localStorage.setItem('accessToken', ''); + localStorage.setItem('username', ''); + localStorage.setItem('expiresIn', ''); + } + } + + static bool isConnected() { + return (localStorage.getItem('accessToken') ?? "") != ""; + } + + static String? getUsername() { + return localStorage.getItem('username'); + } + + static Future login(String username, String password) async { + var token = await service.post("/ldap/login", { + "username": username, + "password": password + }, null); + if (token.code == 200 && token.data != null) { + localStorage.setItem('accessToken', token.data?.value['access_token']); + localStorage.setItem('tokenType', token.data?.value['token_type']); + localStorage.setItem('username', username); + localStorage.setItem('expiresIn', + DateTime.now().add(Duration(seconds: token.data?.value['expires_in'])).toIso8601String()); + HeaderConstants.headerKey.currentState?.setState(() {}); + refresh(token.data?.value['access_token'] ?? "", username, Duration(seconds: token.data?.value['expires_in'])); + } + } + + static Future logout() async { + var token = await service.delete("/ldap/logout", null); + if (token.code == 200 && token.data != null) { + localStorage.setItem('accessToken', ''); + localStorage.setItem('username', ''); + localStorage.setItem('expiresIn', ''); + } + } + + static Future introspect() async { + if (!isConnected()) { + return false; + } + var isIntrospected = await service.get("/introspect", true, null); + return isIntrospected.code == 200; + } + + static Future refresh(String accessToken, String username, Duration duration) async { + print("REFRESH ${duration}"); + Future.delayed(duration, () { + service.post("/refresh", { + "access_token": accessToken, + "username": username + }, null).then((token) { + print("REFRESH ${token.data}"); + if (token.code == 200 && token.data != null) { + localStorage.setItem('accessToken', token.data?.value['access_token']); + localStorage.setItem('username', username); + localStorage.setItem('expiresIn', + DateTime.now().add(Duration(seconds: token.data?.value['expires_in']) - Duration(seconds: 10)).toIso8601String()); + } + }); + }); + } +} \ No newline at end of file diff --git a/lib/core/services/perms_service.dart b/lib/core/services/perms_service.dart new file mode 100644 index 0000000..33b200a --- /dev/null +++ b/lib/core/services/perms_service.dart @@ -0,0 +1,56 @@ +enum Perms { + SEARCH_INTERNAL,// ignore: constant_identifier_names + SEARCH_EXTERNAL, // ignore: constant_identifier_names + + WORKSPACE_SHARE,// ignore: constant_identifier_names + + WORKFLOW_CREATE, // ignore: constant_identifier_names + WORKFLOW_EDIT, // ignore: constant_identifier_names + WORKFLOW_DELETE, // ignore: constant_identifier_names + WORKFLOW_BOOKING, // ignore: constant_identifier_names + WORKFLOW_SHARE, // ignore: constant_identifier_names + + COLLABORATIVE_AREA_CREATE, // ignore: constant_identifier_names + COLLABORATIVE_AREA_EDIT, // ignore: constant_identifier_names + COLLABORATIVE_AREA_DELETE, // ignore: constant_identifier_names +} + +Map perms = { + Perms.SEARCH_INTERNAL: 'Search Internal', + Perms.SEARCH_EXTERNAL: 'Search External', + Perms.WORKSPACE_SHARE: 'Workspace Share', + Perms.WORKFLOW_CREATE: 'Workflow Create', + Perms.WORKFLOW_EDIT: 'Workflow Edit', + Perms.WORKFLOW_DELETE: 'Workflow Delete', + Perms.WORKFLOW_BOOKING: 'Workflow Booking', + Perms.WORKFLOW_SHARE: 'Workflow Share', +}; + +class PermsService { + static const Map _perms = { + Perms.SEARCH_INTERNAL: true, + Perms.SEARCH_EXTERNAL: true, + Perms.WORKSPACE_SHARE: true, + Perms.WORKFLOW_CREATE: true, + Perms.WORKFLOW_EDIT: true, + Perms.WORKFLOW_DELETE: true, + Perms.WORKFLOW_BOOKING: true, + Perms.WORKFLOW_SHARE: true, + + Perms.COLLABORATIVE_AREA_CREATE: true, + Perms.COLLABORATIVE_AREA_EDIT: false, + Perms.COLLABORATIVE_AREA_DELETE: false, + }; + static final PermsService _instance = PermsService._internal(); + factory PermsService() => _instance; + PermsService._internal(); + + static bool getPerm(Perms perm) { + return _perms[perm] ?? false; + } + + static void setPerm(Perms perm, bool value) { + _perms[perm] = value; + } + +} \ No newline at end of file diff --git a/lib/core/services/router.dart b/lib/core/services/router.dart index 2ab42ea..99f7a64 100644 --- a/lib/core/services/router.dart +++ b/lib/core/services/router.dart @@ -53,22 +53,25 @@ class RouterItem { } class AppRouter { - static const String home = "catalog"; + static String home = "catalog"; static final RouterItem workflowItem = RouterItem(icon: Icons.rebase_edit, label: "workflow manager", route: "workflow", factory: WorkflowFactory()); static final RouterItem workflowIDItem = RouterItem(description: "", help: "", route: "workflow/:id", factory: WorkflowFactory(), args: ["id"]); static final RouterItem catalogItem = RouterItem(description: "", help: "", route: "catalog/:id", factory: CatalogItemFactory(), args: ["id"]); - static final RouterItem catalog= RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory()); + static final RouterItem catalog= RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: "catalog", factory: CatalogFactory()); + static final RouterItem scheduler = RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()); + static final RouterItem shared = RouterItem(icon: Icons.share_rounded, label: "collaborative area", route: "shared", factory: SharedFactory()); + static List zones = [ catalog, workflowItem, - RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()), - RouterItem(icon: Icons.dns_outlined, label: "my datacenter", route: "datacenter", - description: "Manage & monitor your datacenter.", help: "not implemented for now", + scheduler, + RouterItem(icon: Icons.dns_outlined, label: "my compute", route: "compute", + description: "Manage & monitor your compute.", help: "not implemented for now", factory: DatacenterFactory()), RouterItem(icon: Icons.public_outlined, label: "localisations", route: "map", factory: MapFactory()), - RouterItem(icon: Icons.share_rounded, label: "collaborative area", route: "shared", factory: SharedFactory()), + shared, workflowIDItem, catalogItem, ]; diff --git a/lib/core/services/specialized_services/shared_service.dart b/lib/core/services/specialized_services/shared_service.dart index 9b9e5b7..d51efd8 100644 --- a/lib/core/services/specialized_services/shared_service.dart +++ b/lib/core/services/specialized_services/shared_service.dart @@ -4,33 +4,33 @@ import 'package:oc_front/core/services/specialized_services/abstract_service.dar import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/shared.dart'; -class SharedService extends AbstractService { - @override APIService service = APIService( +class SharedService extends AbstractService { + @override APIService service = APIService( baseURL: const String.fromEnvironment('COLLABORATIVE_AREA_HOST', defaultValue: 'http://localhost:8080/shared') ); @override String subPath = "/collaborative_area/"; - Future> addWorkspace(BuildContext? context, String id, String id2) { + Future> addWorkspace(BuildContext? context, String id, String id2) { return service.post("$subPath$id/workspace/$id2", {}, context); } - Future> addWorkflow(BuildContext? context, String id, String id2) { + Future> addWorkflow(BuildContext? context, String id, String id2) { return service.post("$subPath$id/workflow/$id2", {}, context); } - Future> addPeer(BuildContext? context, String id, String id2) { + Future> addPeer(BuildContext? context, String id, String id2) { return service.post("$subPath$id/peer/$id2", {}, context); } - Future> removeWorkspace(BuildContext? context, String id, String id2) { + Future> removeWorkspace(BuildContext? context, String id, String id2) { return service.delete("$subPath$id/workspace/$id2", context); } - Future> removeWorkflow(BuildContext? context, String id, String id2) { + Future> removeWorkflow(BuildContext? context, String id, String id2) { return service.delete("$subPath$id/workflow/$id2", context); } - Future> removePeer(BuildContext? context, String id, String id2) { + Future> removePeer(BuildContext? context, String id, String id2) { return service.delete("$subPath$id/peer/$id2", context); } } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 45f697d..55d39ed 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,33 +1,39 @@ +import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; +import 'package:localstorage/localstorage.dart'; import 'package:oc_front/core/models/shared_workspace_local.dart'; import 'package:oc_front/core/models/workspace_local.dart'; +import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/core/sections/header/menu.dart'; +import 'package:oc_front/core/sections/left_menu.dart'; +import 'package:oc_front/core/services/auth.service.dart'; import 'package:oc_front/core/services/router.dart'; import 'package:oc_front/core/sections/end_drawer.dart'; -import 'package:oc_front/core/sections/header/header.dart'; -import 'package:desktop_window/desktop_window.dart' if (kIsWeb) ''; +import 'package:oc_front/widgets/dialog/login.dart'; +void main() async { + WidgetsFlutterBinding.ensureInitialized(); -void main() { + // Run `LinuxWebViewPlugin.initialize()` first before creating a WebView. + await initLocalStorage(); runApp(const MyApp()); } +GlobalKey? mainKey; GlobalKey scaffoldKey = GlobalKey(); class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { - if (!kIsWeb) { DesktopWindow.setMinWindowSize(const Size(400, 400)); } - return MaterialApp.router( - routerConfig: GoRouter( routes: AppRouter.routes ), - ); + AuthService.init(); + return MaterialApp.router( routerConfig: GoRouter( routes: AppRouter.routes ) ); } } // ignore: must_be_immutable class MainPage extends StatefulWidget { - Widget page; - MainPage({super.key, required this.page}); + Widget? page; + MainPage({Key? key, required this.page}) : super(key: GlobalKey()); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect @@ -39,10 +45,40 @@ class MainPage extends StatefulWidget { // always marked "final". @override - State createState() => _MainPageState(); + State createState() => MainPageState(); } -class _MainPageState extends State { +var darkColor = Color.fromRGBO(26, 83, 92, 1); +var lightColor = Color.fromRGBO(78, 205, 196, 1); +var darkMidColor = Color.fromRGBO(44, 83, 100, 1); +var midColor = Colors.grey.shade300; +var redColor = Color.fromRGBO(255, 107, 107, 1); + +double getWidth(BuildContext context) { + return MediaQuery.of(context).size.width <= 800 ? 800 : MediaQuery.of(context).size.width; +} + +double getHeight(BuildContext context) { + return MediaQuery.of(context).size.height <= 400 ? 400 : MediaQuery.of(context).size.height; +} + +double getMainHeight(BuildContext context) { + return getHeight(context) - HeaderConstants.height; +} +double getMainWidth(BuildContext context) { + return getWidth(context) - 50; +} + +class MainPageState extends State { + bool isCtrl = false; + final FocusNode node = FocusNode(); + @override + void initState() { + mainKey = widget.key as GlobalKey?; + node.requestFocus(); + super.initState(); + } + @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done @@ -51,32 +87,62 @@ class _MainPageState extends State { // 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, false); - SharedWorkspaceLocal.init(context, false); scaffoldKey = GlobalKey(); - return Scaffold( - key: scaffoldKey, - endDrawer: EndDrawerWidget(), - body: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: MainAxisAlignment.start, - children: [ - HeaderWidget(), - widget.page // CatalogPageWidget(), - ], - ), - ); + isCtrl = false; + return FutureBuilder(future: AuthService.init(), + builder: (e, s) { + WorkspaceLocal.init(context, false); + CollaborativeAreaLocal.init(context, false); + if (!AuthService.isConnected()) { + Future.delayed(const Duration(milliseconds: 500), () { + showDialog( + barrierDismissible: false, + context: context, builder: (context) { + return AlertDialog( + insetPadding: EdgeInsets.zero, + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), + title: LoginWidget()); + }); + }); + } + HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) || AppRouter.currentRoute.factory.searchFill() ? 50 : 100; + return Scaffold( key: scaffoldKey, endDrawer: EndDrawerWidget(), body: + SingleChildScrollView( + controller: ScrollController(), + scrollDirection: Axis.horizontal, + child: SingleChildScrollView( + child: Column( children: [ + HeaderMenuWidget(), + Row( children : [ + Container( padding: const EdgeInsets.symmetric(vertical: 30), + decoration: BoxDecoration( color: darkColor), + width: 50, height: getHeight(context) - 50, + child: SingleChildScrollView( child: LeftMenuWidget() )), + SizedBox( width: getMainWidth(context), height: getHeight(context) - 50, + child: KeyboardListener( + focusNode: node, + onKeyEvent: (event) async { + if ( event.logicalKey == LogicalKeyboardKey.controlLeft ) { + isCtrl = (event is KeyDownEvent); + node.requestFocus(); + } else if( (event is KeyDownEvent) && event.logicalKey == LogicalKeyboardKey.enter) { + AppRouter.currentRoute.factory.search(context, isCtrl); + node.requestFocus(); + } + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + HeaderWidget(), + widget.page ?? Container() // CatalogPageWidget(), + ], + ), + )), + ]) + ]) + ) + )); + }); } } diff --git a/lib/models/response.dart b/lib/models/response.dart index 87b0d6b..6b09a0d 100644 --- a/lib/models/response.dart +++ b/lib/models/response.dart @@ -10,7 +10,7 @@ Map refs = { Search: Search(), Workspace: Workspace(), DataItem: DataItem(), - DataCenterItem: DataCenterItem(), + ComputeItem: ComputeItem(), StorageItem: StorageItem(), ProcessingItem: ProcessingItem(), Workflow: Workflow(), @@ -18,7 +18,8 @@ Map refs = { WorkflowExecutions: WorkflowExecutions(), LogsResult: LogsResult(), Check: Check(), - SharedWorkspace: SharedWorkspace(), + CollaborativeArea: CollaborativeArea(), + SimpleData: SimpleData(), }; class APIResponse { @@ -40,7 +41,11 @@ class APIResponse { APIResponse deserialize(dynamic j) { dynamic data; - try { data = j["data"]; + try { + if (j["data"] == null) { data = j; } + else { + data = j["data"]; + } } catch (e) { data = j; } try { return APIResponse( @@ -52,6 +57,15 @@ class APIResponse { } } +class SimpleData extends SerializerDeserializer { + SimpleData({ this.value }); + dynamic value; + @override deserialize(dynamic json) { + return SimpleData(value: json); + } + @override Map serialize() => { }; +} + class RawData extends SerializerDeserializer { RawData({ this.values = const []}); List values = []; diff --git a/lib/models/search.dart b/lib/models/search.dart index 48c879f..04eca43 100644 --- a/lib/models/search.dart +++ b/lib/models/search.dart @@ -6,31 +6,31 @@ import 'package:oc_front/models/abstract.dart'; const List _emptyComputing = []; const List _emptyData = []; -const List _emptyDataCenter = []; +const List _emptyCompute = []; const List _emptyStorage = []; class Search extends SerializerDeserializer { Search({ this.computing = _emptyComputing, - this.datacenter = _emptyDataCenter, + this.compute = _emptyCompute, this.data = _emptyData, this.storage = _emptyStorage, }); List computing; - List datacenter; + List compute; List data; List storage; @override deserialize(dynamic json) { json = json as Map; return Search( computing: json.containsKey("processing") ? fromListJson(json["processing"], ProcessingItem()) : [], - datacenter: json.containsKey("datacenter") ? fromListJson(json["datacenter"], DataCenterItem()) : [], + compute: json.containsKey("compute") ? fromListJson(json["compute"], ComputeItem()) : [], data: json.containsKey("data") ? fromListJson(json["data"], DataItem()) : [], storage: json.containsKey("storage") ? fromListJson(json["storage"], StorageItem()) : [], ); } @override Map serialize() => { "processing": toListJson(computing), - "datacenter": toListJson(datacenter), + "compute": toListJson(compute), "data": toListJson(data), "storage": toListJson(storage), }; @@ -41,14 +41,14 @@ class Resource implements SerializerDeserializer { List datas = []; List processings = []; List storages = []; - List datacenters = []; + List computes = []; List workflows = []; Resource({ this.datas = const [], this.processings = const [], this.storages = const [], - this.datacenters = const [], + this.computes = const [], this.workflows = const [], }); @@ -56,7 +56,7 @@ class Resource implements SerializerDeserializer { try { json = json as Map; } catch (e) { return Resource(); } return Resource( - datacenters: json.containsKey("datacenter_resource") ? fromListJson(json["datacenter_resource"], DataCenterItem()) : [], + computes: json.containsKey("compute_resource") ? fromListJson(json["compute_resource"], ComputeItem()) : [], datas: json.containsKey("data_resource") ? fromListJson(json["data_resource"], DataItem()) : [], processings: json.containsKey("processing_resource") ? fromListJson(json["processing_resource"], ProcessingItem()) : [], storages: json.containsKey("storage_resource") ? fromListJson(json["storage_resource"], StorageItem()) : [], @@ -66,7 +66,7 @@ class Resource implements SerializerDeserializer { @override Map serialize() { return { - "datacenter_resource": toListJson(datacenters), + "compute_resource": toListJson(computes), "data_resource": toListJson(datas), "processing_resource": toListJson(processings), "storage_resource": toListJson(storages), @@ -198,7 +198,7 @@ class ResourceModel extends SerializerDeserializer { Type? getTopicType(String topic) { if (topic == "processing") { return ProcessingItem; } else if (topic == "data") { return DataItem; } - else if (topic == "datacenter") { return DataCenterItem; } + else if (topic == "compute") { return ComputeItem; } else if (topic == "storage") { return StorageItem; } else if (topic == "workflow") { return WorkflowItem; } else { return null; } @@ -208,7 +208,7 @@ String getTopic(Type type) { if (type == AbstractItem) { return "resource"; } if (type == ProcessingItem) { return "processing"; } if (type == DataItem) { return "data"; } - if (type == DataCenterItem) { return "datacenter"; } + if (type == ComputeItem) { return "compute"; } if (type == StorageItem) { return "storage"; } if (type == WorkflowItem) { return "workflow"; } return ""; @@ -216,7 +216,7 @@ String getTopic(Type type) { bool isComputing(String topic) => topic == "processing"; bool isData(String topic) => topic == "data"; -bool isDataCenter(String topic) => topic == "datacenter"; +bool isCompute(String topic) => topic == "compute"; bool isStorage(String topic) => topic == "storage"; bool isWorkflow(String topic) => topic == "workflow"; @@ -710,8 +710,8 @@ class DataItem extends SerializerDeserializer implements AbstractItem< }; } -class DataCenterItem extends SerializerDeserializer implements AbstractItem { - DataCenterItem({ +class ComputeItem extends SerializerDeserializer implements AbstractItem { + ComputeItem({ this.id, this.name, this.logo, @@ -728,6 +728,11 @@ class DataCenterItem extends SerializerDeserializer implements A this.cpus = const [], this.gpus = const [], this.ram, + this.technology, + this.access, + this.architecture, + this.localisation, + this.isService = false, }); @override String? id; @override String? name; @@ -735,7 +740,7 @@ class DataCenterItem extends SerializerDeserializer implements A @override String? source; @override String? ownerLogo; @override String? owner; - @override String topic = "datacenter"; + @override String topic = "compute"; @override double? price; @override String? licence; @override List inputs; @@ -743,9 +748,14 @@ class DataCenterItem extends SerializerDeserializer implements A @override String? description; @override String? shortDescription; @override ResourceModel? model; + bool isService = false; + String? architecture; + int? access; + String? localisation; // Special Attributes List cpus = []; List gpus = []; + int? technology; RAM? ram; @override String getID() { return id ?? ""; @@ -763,20 +773,42 @@ class DataCenterItem extends SerializerDeserializer implements A double? getHeight() { return height; } + String getTechnology() { + if (technology == 0) { return "docker"; } + if (technology == 1) { return "kubernetes"; } + if (technology == 2) { return "slurm"; } + if (technology == 3) { return "hardware"; } + if (technology == 4) { return "condor"; } + return ""; + } + String getAccess() { + if (access == 0) { return "ssh"; } + if (access == 1) { return "ssh kube api"; } + if (access == 2) { return "ssh slurm"; } + if (access == 3) { return "ssh docker"; } + if (access == 4) { return "opencloud"; } + if (access == 5) { return "vpn"; } + return ""; + } + @override deserialize(dynamic json) { try { json = json as Map; - } catch (e) { return DataCenterItem(); } - - var w = DataCenterItem( + } catch (e) { return ComputeItem(); } + var w = ComputeItem( + isService: json.containsKey("is_service") ? json["is_service"] : false, id: json.containsKey("id") ? json["id"] : null, name: json.containsKey("name") ? json["name"] : null, logo: json.containsKey("logo") ? json["logo"] : null, + technology: json.containsKey("technology") ? json["technology"] : 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, + access: json.containsKey("access") ? json["access"] : null, + architecture: json.containsKey("architecture") ? json["architecture"] : null, + localisation: json.containsKey("localisation") ? json["localisation"] : null, inputs: json["inputs"] ?? [], outputs: json["outputs"] ?? [], source: json.containsKey("source") ? json["source"] : null, @@ -785,6 +817,7 @@ class DataCenterItem extends SerializerDeserializer implements A gpus: json.containsKey("gpus") ? fromListJson(json["gpus"], GPU()) : [], ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null, ); + print(w.technology); if (w.logo != null) { // var image = Image.network(w.logo!); @@ -829,12 +862,17 @@ class DataCenterItem extends SerializerDeserializer implements A "owner": owner, "owner_logo": ownerLogo, "price": price, + "is_service": isService, "licence": licence, + "access": access, + "architecture": architecture, + "localisation": localisation, "description": description, "short_description": shortDescription, "inputs": inputs, "outputs": outputs, "source": source, + "technology": technology, "resource_model": model?.serialize(), "cpus": toListJson(cpus), "gpus": toListJson(gpus), diff --git a/lib/models/shared.dart b/lib/models/shared.dart index 81567dc..341f967 100644 --- a/lib/models/shared.dart +++ b/lib/models/shared.dart @@ -3,7 +3,7 @@ import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/models/workspace.dart'; -class SharedWorkspace extends SerializerDeserializer { +class CollaborativeArea extends SerializerDeserializer { String? id; String? name; String? description; @@ -15,7 +15,7 @@ class SharedWorkspace extends SerializerDeserializer { List peers = []; List rules = []; - SharedWorkspace( + CollaborativeArea( {this.id, this.name, this.description, @@ -30,8 +30,8 @@ class SharedWorkspace extends SerializerDeserializer { @override deserialize(dynamic json) { try { json = json as Map; - } catch (e) { return SharedWorkspace(); } - return SharedWorkspace( + } catch (e) { return CollaborativeArea(); } + return CollaborativeArea( id: json.containsKey("id") ? json["id"] : null, name: json.containsKey("name") ? json["name"] : null, description: json.containsKey("description") ? json["description"] : null, diff --git a/lib/models/workflow.dart b/lib/models/workflow.dart index 33b7391..c2e5791 100644 --- a/lib/models/workflow.dart +++ b/lib/models/workflow.dart @@ -103,7 +103,7 @@ class Workflow extends SerializerDeserializer implements ShallowData String? id; String? name; List data; - List datacenter; + List compute; List storage; List processing; List workflows; @@ -116,7 +116,7 @@ class Workflow extends SerializerDeserializer implements ShallowData this.id, this.name = "", this.data = const [], - this.datacenter = const [], + this.compute = const [], this.storage = const [], this.processing = const [], this.workflows = const [], @@ -138,7 +138,7 @@ class Workflow extends SerializerDeserializer implements ShallowData name: json.containsKey("name") ? json["name"] : "", workflows: json.containsKey("workflows") ? json["workflows"] : [], processing: json.containsKey("processings") ? json["processings"] : [], - datacenter: json.containsKey("datacenters") ? json["datacenters"] : [], + compute: json.containsKey("computes") ? json["computes"] : [], data: json.containsKey("datas") ? json["datas"] : [], scheduleActive: json.containsKey("schedule_active") ? json["schedule_active"] : false, storage: json.containsKey("storages") ? json["storages"] : [], @@ -152,7 +152,7 @@ class Workflow extends SerializerDeserializer implements ShallowData "id": id, "name": name, "datas": data, - "datacenters" : datacenter, + "computes" : compute, "storages": storage, "processings": processing, "workflows": workflows, @@ -497,7 +497,7 @@ class GraphItem extends SerializerDeserializer { DataItem? data; ProcessingItem? processing; StorageItem? storage; - DataCenterItem? datacenter; + ComputeItem? compute; WorkflowItem? workflow; GraphItem({ @@ -508,7 +508,7 @@ class GraphItem extends SerializerDeserializer { this.data, this.processing, this.storage, - this.datacenter, + this.compute, this.workflow, }); @@ -516,7 +516,7 @@ class GraphItem extends SerializerDeserializer { if (data != null) { return data!; } if (processing != null) { return processing!; } if (storage != null) { return storage!; } - if (datacenter != null) { return datacenter!; } + if (compute != null) { return compute!; } if (workflow != null) { return workflow!; } return null; } @@ -542,21 +542,21 @@ class GraphItem extends SerializerDeserializer { processing!.expose.removeWhere((element) => element.port == null || element.port == 0 || (element.PAT == 0 && element.path == "")); } - } else if (abs.topic == "datacenter") { - datacenter = DataCenterItem().deserialize(abs.serialize()); + } else if (abs.topic == "compute") { + compute = ComputeItem().deserialize(abs.serialize()); } else if (abs.topic == "storage") { storage = StorageItem().deserialize(abs.serialize()); } else if (abs.topic == "workflow") { workflow = WorkflowItem().deserialize(abs.serialize()); } else { - datacenter = null; + compute = null; data = null; processing = null; storage = null; workflow = null; } } else { - datacenter = null; + compute = null; data = null; processing = null; storage = null; @@ -566,7 +566,7 @@ class GraphItem extends SerializerDeserializer { Map toDashboard() { Map element = {}; - for(var el in [data, processing, storage, datacenter, workflow]) { + for(var el in [data, processing, storage, compute, workflow]) { if (el != null && el.getID() != "") { element = el.serialize(); break; @@ -593,7 +593,7 @@ class GraphItem extends SerializerDeserializer { 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, + compute: json.containsKey("compute") ? ComputeItem().deserialize(json["compute"]) : null, workflow: json.containsKey("workflow") ? WorkflowItem().deserialize(json["workflow"]) : null, ); } @@ -605,7 +605,7 @@ class GraphItem extends SerializerDeserializer { "data": data?.serialize(), "processing": processing?.serialize(), "storage": storage?.serialize(), - "datacenter": datacenter?.serialize(), + "compute": compute?.serialize(), "workflow": workflow?.serialize(), "position": position?.serialize(), }; diff --git a/lib/models/workspace.dart b/lib/models/workspace.dart index 144721a..755ebd4 100644 --- a/lib/models/workspace.dart +++ b/lib/models/workspace.dart @@ -8,7 +8,7 @@ class Workspace extends SerializerDeserializer implements ShallowData String? name; bool? active; List datas; - List datacenters; + List computes; List storages; List processings; List workflows; @@ -20,7 +20,7 @@ class Workspace extends SerializerDeserializer implements ShallowData this.active = false, this.workflows = const [], this.datas = const [], - this.datacenters = const [], + this.computes = const [], this.storages = const [], this.processings = const [], this.shared, @@ -39,7 +39,7 @@ class Workspace extends SerializerDeserializer implements ShallowData 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()) : [], + computes: json.containsKey("compute_resources") ? fromListJson(json["compute_resources"], ComputeItem()) : [], datas: json.containsKey("data_resources") ? fromListJson(json["data_resources"], DataItem()) : [], workflows: json.containsKey("workflow_resources") ? fromListJson(json["workflow_resources"], WorkflowItem()) : [] ); @@ -49,7 +49,7 @@ class Workspace extends SerializerDeserializer implements ShallowData "name": name, "processings": processings.map((e) => e.id).toList(), "storages": storages.map((e) => e.id).toList(), - "datacenters": datacenters.map((e) => e.id).toList(), + "computes": computes.map((e) => e.id).toList(), "datas": datas.map((e) => e.id).toList(), "workflows": workflows.map((e) => e.id).toList(), }; diff --git a/lib/pages/abstract_page.dart b/lib/pages/abstract_page.dart index 39b605f..d65b56c 100644 --- a/lib/pages/abstract_page.dart +++ b/lib/pages/abstract_page.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; abstract class AbstractFactory { + GlobalKey getKey(); Widget factory(GoRouterState state, List args); bool searchFill(); - void search(BuildContext context); + void search(BuildContext context, bool special); + void clear(); } \ No newline at end of file diff --git a/lib/pages/catalog.dart b/lib/pages/catalog.dart index 02c9a58..ab42da2 100644 --- a/lib/pages/catalog.dart +++ b/lib/pages/catalog.dart @@ -1,38 +1,41 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:oc_front/core/models/shared_workspace_local.dart'; -import 'package:oc_front/core/models/workspace_local.dart'; import 'package:oc_front/core/sections/header/header.dart'; import 'package:oc_front/core/services/specialized_services/resource_service.dart'; -import 'package:oc_front/core/services/specialized_services/shared_service.dart'; -import 'package:oc_front/core/services/specialized_services/workspace_service.dart'; -import 'package:oc_front/models/response.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/search.dart'; -import 'package:oc_front/pages/shared.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/widgets/inputs/shallow_dropdown_input.dart'; -import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; class CatalogFactory implements AbstractFactory { - static List items = []; + @override GlobalKey getKey() { return key; } static GlobalKey key = GlobalKey(); - @override bool searchFill() { return CatalogFactory.items.isEmpty; } + @override void clear() { + mainKey?.currentState?.setState(() { + HeaderConstants.headerKey.currentState?.setState(() {}); + HeaderConstants.headerWidget?.setState(() {}); + key.currentState?.widget.items = []; + }); + } + @override bool searchFill() { return key.currentState?.widget.items.isEmpty ?? true; } @override Widget factory(GoRouterState state, List args) { return CatalogPageWidget(); } - @override void search(BuildContext context) { + @override void search(BuildContext context, bool special) { + if (special) { return; } CatalogFactory.key.currentState?.widget.search.search(context, [ SearchConstants.get()! ], {}).then((value) { if (value.data == null) { return; } - CatalogFactory.items = [ ...value.data!.workflows, - ...value.data!.processings, ...value.data!.datas, ...value.data!.storages, ...value.data!.datacenters,]; - searchWidgetKey.currentState?.setState(() {}); - CatalogFactory.key.currentState?.setState(() {}); + key.currentState?.widget.items = [ ...value.data!.workflows, + ...value.data!.processings, ...value.data!.datas, ...value.data!.storages, ...value.data!.computes,]; + HeaderConstants.headerKey.currentState?.setState(() {}); + HeaderConstants.headerWidget?.setState(() {}); + CatalogFactory.key.currentState?.setState(() {}); // ignore: invalid_use_of_protected_member }); } } +// ignore: must_be_immutable class CatalogPageWidget extends StatefulWidget { double? itemWidth; + List items = []; final ResourceService search = ResourceService(); CatalogPageWidget ({ this.itemWidth, @@ -41,76 +44,45 @@ class CatalogPageWidget extends StatefulWidget { } class CatalogPageWidgetState extends State { @override Widget build(BuildContext context) { + if (widget.items.isEmpty) { return Container(); } return Column( children : [ - CatalogFactory.items.isEmpty ? Container() : - Row( children: [ - ShallowDropdownInputWidget( - current: WorkspaceLocal.current, - width: MediaQuery.of(context).size.width / 3, - all: () async => WorkspaceLocal.getWorkspacesShallow(), - type: SharedWorkspaceType.workspace, - change: (String? change) { - WorkspaceLocal.changeWorkspace(change.toString()); - }, - color: Colors.white, - filled: const Color.fromRGBO(38, 166, 154, 1), - hintColor: Colors.grey.shade300, - canRemove: (String? remove) => remove != null, - remove: (String? remove) async { - if (remove == null) { return; } - WorkspaceLocal.deleteWorkspace(remove); - }, - ), - ShallowTextInputWidget( - width: MediaQuery.of(context).size.width / 3, - type: SharedWorkspaceType.workspace, - color: Colors.white, - filled: const Color.fromRGBO(38, 166, 154, 1), - hintColor: Colors.grey.shade300, - canRemove: (p0) => p0 != null, - remove: (p0) async { - await WorkspaceService().delete(context, p0, {}).then( (e) => WorkspaceLocal.deleteWorkspace(p0)); - }, - canLoad: (String? remove) => remove != null, - load: (Map add) async { - if (add["name"] == null) { return; } - WorkspaceLocal.createWorkspace(add["name"], context); - }, - ), - ShallowDropdownInputWidget( + SizedBox( + width: getMainWidth(context), + height: getMainHeight(context), + child: SingleChildScrollView( child: CatalogWidget(items: CatalogFactory.key.currentState?.widget.items, itemWidth: widget.itemWidth) )), + ] + ); + } +} +/* + + PermsService.getPerm(Perms.WORKSPACE_SHARE) ? ShallowDropdownInputWidget( iconLoad: Icons.share_rounded, - tooltipLoad: 'share', + tooltipLoad: 'share', tooltipRemove: 'unshare', color: Colors.white, filled: const Color.fromRGBO(38, 166, 154, 1), - hintColor: Colors.grey.shade300, - type: SharedWorkspaceType.workspace, - all: () async => SharedWorkspaceLocal.workspaces.values.map( + hintColor: midColor, + type: CollaborativeAreaType.workspace, + all: () async => CollaborativeAreaLocal.workspaces.values.map( (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), current: WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared, - width: (MediaQuery.of(context).size.width / 3), - canLoad: (String? change) => SharedWorkspaceLocal.workspaces[change] == null - || !SharedWorkspaceLocal.workspaces[change]!.workspaces.map( + width: (getMainWidth(context) / 3), + canLoad: (String? change) => CollaborativeAreaLocal.workspaces[change] == null + || !CollaborativeAreaLocal.workspaces[change]!.workspaces.map( (e) => e.id ).contains(WorkspaceLocal.current), - canRemove: (String? change) => SharedWorkspaceLocal.workspaces[change] == null - || SharedWorkspaceLocal.workspaces[change]!.workspaces.map( + canRemove: (String? change) => CollaborativeAreaLocal.workspaces[change] == null + || CollaborativeAreaLocal.workspaces[change]!.workspaces.map( (e) => e.id ).contains(WorkspaceLocal.current), load: (String val) async { await SharedService().addWorkspace(context, val, WorkspaceLocal.current ?? ""); // ignore: use_build_context_synchronously - SharedWorkspaceLocal.init(context, false); + CollaborativeAreaLocal.init(context, false); }, remove: (String val) async { await SharedService().removeWorkspace(context, val, WorkspaceLocal.current ?? ""); // ignore: use_build_context_synchronously - SharedWorkspaceLocal.init(context, false); - }) - ]), - SizedBox( - width: MediaQuery.of(context).size.width, - height: CatalogFactory.items.isEmpty ? 0 : MediaQuery.of(context).size.height - HeaderConstants.height - 50, - child: SingleChildScrollView( child: CatalogWidget(items: CatalogFactory.items, itemWidth: widget.itemWidth) )), - ] - ); - } -} \ No newline at end of file + CollaborativeAreaLocal.init(context, false); + }) : Container(width: (getMainWidth(context) / 3), height: 50, + color: const Color.fromRGBO(38, 166, 154, 1)), +*/ \ No newline at end of file diff --git a/lib/pages/catalog_item.dart b/lib/pages/catalog_item.dart index 7a51e3b..7b5f1ff 100644 --- a/lib/pages/catalog_item.dart +++ b/lib/pages/catalog_item.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:oc_front/core/models/workspace_local.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/pages/abstract_page.dart'; import 'package:oc_front/pages/catalog.dart'; @@ -9,19 +10,21 @@ import 'package:oc_front/widgets/items/item_row.dart'; class CatalogItemFactory implements AbstractFactory { static GlobalKey key = GlobalKey(); + @override void clear() { } + @override GlobalKey getKey() { return key; } @override bool searchFill() { return false; } @override Widget factory(GoRouterState state, List args) { var id = state.pathParameters[args.first]; try { - var item = CatalogFactory.items.firstWhere( (element) => element.id == id ); - return CatalogItemPageWidget(item : item); + var item = CatalogFactory.key.currentState?.widget.items.firstWhere( (element) => element.id == id ); + return CatalogItemPageWidget(item : item!); } catch (e) { var item = WorkspaceLocal.getItem(id ?? "", false); if (item != null) { return CatalogItemPageWidget(item : item as AbstractItem); } return Container(); } } - @override void search(BuildContext context) { } + @override void search(BuildContext context, bool special) { } } class CatalogItemPageWidget extends StatefulWidget { @@ -32,7 +35,7 @@ class CatalogItemPageWidget extends StatefulWidget { class CatalogItemPageWidgetState extends State { @override Widget build(BuildContext context) { return Column( children: [ - ItemRowWidget(contextWidth: MediaQuery.of(context).size.width, item: widget.item, readOnly: true,), + ItemRowWidget(contextWidth: getMainWidth(context), item: widget.item, readOnly: true,), ItemWidget(item: widget.item,), ]); } diff --git a/lib/pages/datacenter.dart b/lib/pages/datacenter.dart index 7b9916a..ce567fd 100644 --- a/lib/pages/datacenter.dart +++ b/lib/pages/datacenter.dart @@ -3,19 +3,21 @@ import 'package:go_router/go_router.dart'; import 'package:oc_front/pages/abstract_page.dart'; class DatacenterFactory implements AbstractFactory { - static GlobalKey key = GlobalKey(); + @override GlobalKey getKey() { return key; } + @override void clear() { } + static GlobalKey key = GlobalKey(); @override bool searchFill() { return false; } - @override Widget factory(GoRouterState state, List args) { return DataCenterPageWidget(); } - @override void search(BuildContext context) { } + @override Widget factory(GoRouterState state, List args) { return ComputePageWidget(); } + @override void search(BuildContext context, bool special) { } } -class DataCenterPageWidget extends StatefulWidget { - DataCenterPageWidget () : super(key: DatacenterFactory.key); - @override DataCenterPageWidgetState createState() => DataCenterPageWidgetState(); +class ComputePageWidget extends StatefulWidget { + ComputePageWidget () : super(key: DatacenterFactory.key); + @override ComputePageWidgetState createState() => ComputePageWidgetState(); - static Widget factory() { return DataCenterPageWidget(); } + static Widget factory() { return ComputePageWidget(); } } -class DataCenterPageWidgetState extends State { +class ComputePageWidgetState extends State { @override Widget build(BuildContext context) { return Column( children: []); } diff --git a/lib/pages/map.dart b/lib/pages/map.dart index 881e0ba..7a32169 100644 --- a/lib/pages/map.dart +++ b/lib/pages/map.dart @@ -5,10 +5,12 @@ import 'package:flutter_map/flutter_map.dart'; import 'package:oc_front/pages/abstract_page.dart'; class MapFactory implements AbstractFactory { + @override GlobalKey getKey() { return key; } + @override void clear() { } static GlobalKey key = GlobalKey(); @override bool searchFill() { return false; } @override Widget factory(GoRouterState state, List args) { return MapPageWidget(); } - @override void search(BuildContext context) { } + @override void search(BuildContext context, bool special) { } } class MapPageWidget extends StatefulWidget { diff --git a/lib/pages/scheduler.dart b/lib/pages/scheduler.dart index 91678e3..be57664 100644 --- a/lib/pages/scheduler.dart +++ b/lib/pages/scheduler.dart @@ -4,15 +4,18 @@ import 'package:intl/intl.dart' as intl; import 'package:go_router/go_router.dart'; import 'package:oc_front/core/services/specialized_services/logs_service.dart'; import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/abstract_page.dart'; import 'package:oc_front/widgets/sheduler_items/schedule.dart'; class SchedulerFactory implements AbstractFactory { + @override GlobalKey getKey() { return key; } + @override void clear() { } static GlobalKey key = GlobalKey(); @override bool searchFill() { return false; } @override Widget factory(GoRouterState state, List args) { return SchedulerPageWidget(); } - @override void search(BuildContext context) { } + @override void search(BuildContext context, bool special) { } } class SchedulerPageWidget extends StatefulWidget { @@ -26,7 +29,7 @@ class SchedulerPageWidget extends StatefulWidget { static Widget factory() { return SchedulerPageWidget(); } } class SchedulerPageWidgetState extends State { - List colors = [Colors.blue, Colors.orange, Colors.red, Colors.green]; + List colors = [Colors.blue, Colors.orange, redColor, Colors.green]; List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"]; @override Widget build(BuildContext context) { @@ -92,8 +95,8 @@ class SchedulerPageWidgetState extends State { } } return Column( children: [ - Container( color: const Color.fromRGBO(38, 166, 154, 1), - height: 50, width: MediaQuery.of(context).size.width, + Container( color: lightColor, + height: 50, width: getMainWidth(context), child: Padding(padding: const EdgeInsets.symmetric(horizontal: 50), child: Row( children: [ Padding(padding: const EdgeInsets.only(right: 30), @@ -107,7 +110,7 @@ class SchedulerPageWidgetState extends State { ), ), Container(padding: const EdgeInsets.only(left: 20), - width: MediaQuery.of(context).size.width / 5, + width: getMainWidth(context) / 5, height: 30, child: DateTimeField( validator: (value) { @@ -122,7 +125,7 @@ class SchedulerPageWidgetState extends State { 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, + background: midColor, tertiary: Colors.grey, secondary: Colors.grey, primary: Colors.black), @@ -165,7 +168,7 @@ class SchedulerPageWidgetState extends State { Container(padding: const EdgeInsets.only(left: 20), child: const Text("TO", style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w500))), Container( padding: const EdgeInsets.only(left: 20, right: 20), - width: MediaQuery.of(context).size.width / 5, + width: getMainWidth(context) / 5, height: 30, child: DateTimeField( validator: (value) { @@ -180,7 +183,7 @@ class SchedulerPageWidgetState extends State { 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, + background: midColor, tertiary: Colors.grey, secondary: Colors.grey, primary: Colors.black), diff --git a/lib/pages/shared.dart b/lib/pages/shared.dart index c53c5a2..57af466 100644 --- a/lib/pages/shared.dart +++ b/lib/pages/shared.dart @@ -5,10 +5,12 @@ import 'package:go_router/go_router.dart'; import 'package:oc_front/core/models/shared_workspace_local.dart'; import 'package:oc_front/core/models/workspace_local.dart'; import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/core/services/perms_service.dart'; import 'package:oc_front/core/services/router.dart'; import 'package:oc_front/core/services/specialized_services/peer_service.dart'; import 'package:oc_front/core/services/specialized_services/shared_service.dart'; import 'package:oc_front/core/services/specialized_services/workflow_service.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/shared.dart'; import 'package:oc_front/pages/abstract_page.dart'; @@ -18,17 +20,19 @@ import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; import 'package:oc_front/widgets/items/shallow_item_row.dart'; import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; -enum SharedWorkspaceType { global, shared_workspace, workspace, workflow, peer, resource } +enum CollaborativeAreaType { global, collaborative_area, workspace, workflow, peer, resource } class SharedFactory implements AbstractFactory { + @override GlobalKey getKey() { return key; } + @override void clear() { } static GlobalKey key = GlobalKey(); @override bool searchFill() { return false; } @override Widget factory(GoRouterState state, List args) { return SharedPageWidget(); } - @override void search(BuildContext context) { } + @override void search(BuildContext context, bool special) { } } class SharedPageWidget extends StatefulWidget { - SharedWorkspaceType type = SharedWorkspaceType.global; + CollaborativeAreaType type = CollaborativeAreaType.global; SharedPageWidget(): super(key: SharedFactory.key); @override SharedPageWidgetState createState() => SharedPageWidgetState(); static void search(BuildContext context) { } @@ -36,15 +40,15 @@ class SharedPageWidget extends StatefulWidget { } class SharedPageWidgetState extends State { SharedService service = SharedService(); - Widget getMenuItem(SharedWorkspaceType workspaceType, IconData icon) { - var s = workspaceType == SharedWorkspaceType.global ? "dashboard" : workspaceType == SharedWorkspaceType.workspace ? "shared workspaces" : workspaceType == SharedWorkspaceType.workflow ? "shared workflows" : "peers engaged"; + Widget getMenuItem(CollaborativeAreaType workspaceType, IconData icon) { + var s = workspaceType == CollaborativeAreaType.global ? "dashboard" : workspaceType == CollaborativeAreaType.workspace ? "shared workspaces" : workspaceType == CollaborativeAreaType.workflow ? "shared workflows" : "peers engaged"; return Tooltip( message: s, child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () => setState(() { widget.type = workspaceType; }), child: Container( width: 50, height: 50, - color: widget.type == workspaceType ? Color.fromRGBO(38, 166, 154, 1) : Colors.transparent, + color: widget.type == workspaceType ? darkColor : Colors.transparent, padding: const EdgeInsets.symmetric(vertical: 10), child : Icon(icon, color: widget.type == workspaceType ? Colors.white : Colors.white, size: 20)))); @@ -52,9 +56,9 @@ class SharedPageWidgetState extends State { @override Widget build(BuildContext context) { GlobalKey key = GlobalKey(); - if (SharedWorkspaceLocal.current == null) { + if (CollaborativeAreaLocal.current == null) { Future.delayed( const Duration(microseconds: 100), () { - HeaderConstants.setTitle("Choose a Shared Workspace"); + HeaderConstants.setTitle("Choose a Collaborative Area"); HeaderConstants.setDescription("select a shared workspace to continue"); }); Future.delayed( const Duration(milliseconds: 100), () { @@ -67,78 +71,90 @@ class SharedPageWidgetState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), title: ShallowCreationDialogWidget( formKey: key, - canClose: () => SharedWorkspaceLocal.current != null, + canClose: () => CollaborativeAreaLocal.current != null, context: context, load: (p0) async { - SharedWorkspaceLocal.current = p0; - HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); - HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); + CollaborativeAreaLocal.current = p0; + HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>"); + HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? ""); Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); }, form: [ ShallowTextInputWidget( change :(p0) => key.currentState?.setState(() {}), canLoad: (po) => po != null && po.isNotEmpty, - type: SharedWorkspaceType.shared_workspace, - width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, + type: CollaborativeAreaType.collaborative_area, + width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400, attr: "description", color: Colors.black, hintColor: Colors.grey, - filled: Colors.grey.shade300, + hint: "enter collaborative area description...", + filled: midColor, ) ], - create: (p0) async => await SharedService().post(context, p0, {}).then((value) { + create: PermsService.getPerm(Perms.COLLABORATIVE_AREA_CREATE) ? (p0) async => await SharedService().post(context, p0, {}).then((value) { if (value.data != null) { - SharedWorkspaceLocal.current = value.data!.id; + CollaborativeAreaLocal.current = value.data!.id; } - SharedWorkspaceLocal.init(context, true); + CollaborativeAreaLocal.init(context, true); - HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); - HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); + HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>"); + HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? ""); Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); - }), - type: SharedWorkspaceType.shared_workspace, - all: () async => SharedWorkspaceLocal.workspaces.values.map( + }) : null, + type: CollaborativeAreaType.collaborative_area, + all: () async => CollaborativeAreaLocal.workspaces.values.map( (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), ))); }); } else { Future.delayed( const Duration(milliseconds: 100), () { - HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); - HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); + HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>"); + HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? ""); }); } Widget w = WorkspaceSharedPageWidget(type: widget.type); List addMenu = []; - SharedWorkspace? current = SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current ?? ""]; - if (widget.type == SharedWorkspaceType.workspace) { + CollaborativeArea? current = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]; + if (widget.type == CollaborativeAreaType.workspace) { addMenu.add( Row( mainAxisAlignment: MainAxisAlignment.end, - children : [ ShallowDropdownInputWidget( + children : [ Container( padding: EdgeInsets.only(left: 20), decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.white)) + ), child: ShallowDropdownInputWidget( tooltipLoad: "share", tooltipRemove: "unshare", iconLoad: Icons.share, type: widget.type, + filled: lightColor, + hintColor: midColor, + color: Colors.white, + prefixIcon: Icon(Icons.shopping_cart, color: Colors.white), current: WorkspaceLocal.current, all: () async => WorkspaceLocal.getWorkspacesShallow(), - width: MediaQuery.of(context).size.width / 3, + width: getMainWidth(context) / 3, canLoad: (String? change) => current == null || !current.workspaces.map( (e) => e.id ).contains(change), canRemove: (String? change) => current == null || current.workspaces.map( (e) => e.id ).contains(change), load: (String val) async { - await service.addWorkspace(context, SharedWorkspaceLocal.current ?? "", val); - SharedWorkspaceLocal.init(context, false); + await service.addWorkspace(context, CollaborativeAreaLocal.current ?? "", val); + CollaborativeAreaLocal.init(context, false); }, remove: (String val) async { - await service.removeWorkspace(context, SharedWorkspaceLocal.current ?? "", val); - SharedWorkspaceLocal.init(context, false); - }) + await service.removeWorkspace(context, CollaborativeAreaLocal.current ?? "", val); + CollaborativeAreaLocal.init(context, false); + })) ])); } - if (widget.type == SharedWorkspaceType.workflow) { + if (widget.type == CollaborativeAreaType.workflow) { addMenu.add( Row( mainAxisAlignment: MainAxisAlignment.end, - children : [ ShallowDropdownInputWidget( + children : [ Container( padding: EdgeInsets.only(left: 20), decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.white)) + ), child: ShallowDropdownInputWidget( tooltipLoad: "share", tooltipRemove: "unshare", iconLoad: Icons.share, + filled: lightColor, + hintColor: midColor, + color: Colors.white, type: widget.type, all: () async { List shals = []; await WorflowService().all(context).then((value) { @@ -148,22 +164,28 @@ class SharedPageWidgetState extends State { }); return shals; }, - width: MediaQuery.of(context).size.width / 3, + width: getMainWidth(context) / 3, canLoad: (String? change) => current == null || !current.workflows.map( (e) => e.id ).contains(change), canRemove: (String? change) => current == null || current.workflows.map( (e) => e.id ).contains(change), load: (String change) async { - await service.addWorkflow(context, SharedWorkspaceLocal.current ?? "", change); + await service.addWorkflow(context, CollaborativeAreaLocal.current ?? "", change); }, remove: (String change) async { - await service.removeWorkflow(context, SharedWorkspaceLocal.current ?? "", change); - }) + await service.removeWorkflow(context, CollaborativeAreaLocal.current ?? "", change); + })) ])); } - if (widget.type == SharedWorkspaceType.peer) { + if (widget.type == CollaborativeAreaType.peer) { addMenu.add( Row( mainAxisAlignment: MainAxisAlignment.end, - children : [ ShallowDropdownInputWidget( + children : [ + Container( padding: EdgeInsets.only(left: 20), decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.white)) + ), child: ShallowDropdownInputWidget( tooltipLoad: "add", iconLoad: Icons.add, + filled: lightColor, + hintColor: midColor, + color: Colors.white, type: widget.type, all: () async { List shals = []; await PeerService().all(context).then((value) { @@ -173,22 +195,22 @@ class SharedPageWidgetState extends State { }); return shals; }, - width: MediaQuery.of(context).size.width / 3, + width: getMainWidth(context) / 3, canLoad: (String? change) => current == null || !current.peers.map( (e) => e.id ).contains(change), canRemove: (String? change) => current == null || current.peers.map( (e) => e.id ).contains(change), load: (String change) async { - await service.addPeer(context, SharedWorkspaceLocal.current ?? "", change); + await service.addPeer(context, CollaborativeAreaLocal.current ?? "", change); }, remove: (String change) async { - await service.removePeer(context, SharedWorkspaceLocal.current ?? "", change); - }) + await service.removePeer(context, CollaborativeAreaLocal.current ?? "", change); + })) ])); } return Column( children: [ Container( height: 50, - color: const Color.fromRGBO(38, 166, 154, 1), - width: MediaQuery.of(context).size.width, + color: lightColor, + width: getMainWidth(context), padding: const EdgeInsets.only(left: 50), child: Stack( alignment: Alignment.centerLeft, children: [ Tooltip( message: "open file", child: Padding( padding: const EdgeInsets.only(right: 15), @@ -204,37 +226,37 @@ class SharedPageWidgetState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), title: ShallowCreationDialogWidget( formKey: key, - canClose: () => SharedWorkspaceLocal.current != null, + canClose: () => CollaborativeAreaLocal.current != null, context: context, load: (p0) async { - SharedWorkspaceLocal.current = p0; - HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); - HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); + CollaborativeAreaLocal.current = p0; + HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>"); + HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? ""); Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); }, form: [ ShallowTextInputWidget( change :(p0) => key.currentState?.setState(() {}), - type: SharedWorkspaceType.shared_workspace, - width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, + type: CollaborativeAreaType.collaborative_area, + width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400, attr: "description", color: Colors.black, hintColor: Colors.grey, - filled: Colors.grey.shade300, + filled: midColor, ) ], - create: (p0) async => await SharedService().post(context, p0, {}).then( (e) { + create: PermsService.getPerm(Perms.COLLABORATIVE_AREA_CREATE) ? (p0) async => await SharedService().post(context, p0, {}).then( (e) { if (e.data != null) { - SharedWorkspaceLocal.current = e.data!.id; + CollaborativeAreaLocal.current = e.data!.id; } - SharedWorkspaceLocal.init(context, true); + CollaborativeAreaLocal.init(context, true); - HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); - HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); + HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>"); + HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? ""); Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); - }), - type: SharedWorkspaceType.shared_workspace, - all: () async => SharedWorkspaceLocal.workspaces.values.map( + }) : null, + type: CollaborativeAreaType.collaborative_area, + all: () async => CollaborativeAreaLocal.workspaces.values.map( (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), )); }); @@ -245,21 +267,24 @@ class SharedPageWidgetState extends State { Row( children: [ Container( - color: Colors.black, - height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, + decoration: BoxDecoration( + color: Colors.black, + border: Border(left: BorderSide(color: lightColor)) + ), + height: getMainHeight(context) - 50, width: 50, child: Column( children: [ - getMenuItem(SharedWorkspaceType.global, Icons.dashboard), - getMenuItem(SharedWorkspaceType.workspace, Icons.workspaces), - getMenuItem(SharedWorkspaceType.workflow, Icons.rebase_edit), - getMenuItem(SharedWorkspaceType.peer, Icons.group), + getMenuItem(CollaborativeAreaType.global, Icons.dashboard), + getMenuItem(CollaborativeAreaType.workspace, Icons.workspaces), + getMenuItem(CollaborativeAreaType.workflow, Icons.rebase_edit), + getMenuItem(CollaborativeAreaType.peer, Icons.group), ]) ), Container( - height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, - width: MediaQuery.of(context).size.width -50, - color: widget.type == SharedWorkspaceType.workflow || widget.type == SharedWorkspaceType.peer ? Colors.grey.shade300 : Colors.white, + height: getMainHeight(context) - 50, + width: getMainWidth(context) -50, + color: widget.type == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer ? midColor : Colors.white, child: SingleChildScrollView( child: w )) ] ) ] @@ -268,40 +293,40 @@ class SharedPageWidgetState extends State { } class WorkspaceSharedPageWidget extends StatefulWidget { - SharedWorkspaceType type = SharedWorkspaceType.global; + CollaborativeAreaType type = CollaborativeAreaType.global; WorkspaceSharedPageWidget({ required this.type }): super(key: null); @override WorkspaceSharedPageWidgetState createState() => WorkspaceSharedPageWidgetState(); } class WorkspaceSharedPageWidgetState extends State { @override Widget build(BuildContext context) { - if (SharedWorkspaceLocal.current == null) { + if (CollaborativeAreaLocal.current == null) { return Container(); } - var space = SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current ?? ""]!; + var space = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]!; List items = []; List data = []; - if (widget.type == SharedWorkspaceType.global) { - } else if (widget.type == SharedWorkspaceType.workspace) { + if (widget.type == CollaborativeAreaType.global) { + } else if (widget.type == CollaborativeAreaType.workspace) { data = space.workspaces; - } else if (widget.type == SharedWorkspaceType.workflow) { + } else if (widget.type == CollaborativeAreaType.workflow) { data = space.workflows; - } else if (widget.type == SharedWorkspaceType.peer) { + } else if (widget.type == CollaborativeAreaType.peer) { data = space.peers; } - var current = SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]; + var current = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]; for (var w in data) { - if (widget.type == SharedWorkspaceType.workspace) { + if (widget.type == CollaborativeAreaType.workspace) { if (WorkspaceLocal.workspaces[w.getID()] == null) { continue; } items.add(WorkspaceSharedItemPageWidget(name: "Workspace <${WorkspaceLocal.workspaces[w.getID()]!.name}>", id: w.getID())); - } else if (widget.type == SharedWorkspaceType.workflow || widget.type == SharedWorkspaceType.peer) { + } else if (widget.type == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer) { List badges = []; - if (widget.type == SharedWorkspaceType.peer && w.getID() == current?.creatorID) { + if (widget.type == CollaborativeAreaType.peer && w.getID() == current?.creatorID) { badges.add(Icons.star); } items.add(ShallowItemRowWidget( item: w, badges: badges, - edit: widget.type == SharedWorkspaceType.workflow ? (String? change) { + edit: widget.type == CollaborativeAreaType.workflow ? (String? change) { if (change != null) { WorkspaceLocal.changeWorkspaceByName(change.split("~")[1]); } @@ -309,27 +334,27 @@ class WorkspaceSharedPageWidgetState extends State { } : null, delete: (String? change) async { if (change == null) { return; } - if (widget.type == SharedWorkspaceType.peer) { - await SharedService().removePeer(context, SharedWorkspaceLocal.current ?? "", change); + if (widget.type == CollaborativeAreaType.peer) { + await SharedService().removePeer(context, CollaborativeAreaLocal.current ?? "", change); } else { - await SharedService().removePeer(context, SharedWorkspaceLocal.current ?? "", change); + await SharedService().removePeer(context, CollaborativeAreaLocal.current ?? "", change); } }, - icon: widget.type == SharedWorkspaceType.workflow ? Icons.work_history_rounded : Icons.person, + icon: widget.type == CollaborativeAreaType.workflow ? Icons.work_history_rounded : Icons.person, contextWidth: 200) ); } } if (items.isEmpty) { return Container( - color: Colors.grey.shade300, - height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, - width: MediaQuery.of(context).size.width - 50, + color: midColor, + height: getMainHeight(context) - 50, + width: getMainWidth(context) - 50, alignment: Alignment.center, padding: const EdgeInsets.all(50), child: Text("NO ITEMS SHARED", style: const TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white))); } - if (widget.type == SharedWorkspaceType.workflow || widget.type == SharedWorkspaceType.peer) { + if (widget.type == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer) { return Padding( padding: const EdgeInsets.all(50), child: Stack( alignment: Alignment.topLeft, children : items)); @@ -349,10 +374,10 @@ class WorkspaceSharedItemPageWidgetState extends State key = GlobalKey(); @override bool searchFill() { return false; } @override Widget factory(GoRouterState state, List args) { @@ -29,7 +32,7 @@ class WorkflowFactory implements AbstractFactory { } catch (e) { } return WorkflowPageWidget(id: id); } - @override void search(BuildContext context) { } + @override void search(BuildContext context, bool special) { } } bool getAll = true; @@ -45,7 +48,7 @@ final WorflowService _service = WorflowService(); Widget itemBuild(Object item) { var e = item as AbstractItem; return Tooltip( message: item.name ?? "", - child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill) + child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill) : Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', fit: BoxFit.fill)); } @@ -63,6 +66,8 @@ final WorflowService _service = WorflowService(); res = [DataFormsWidget(item: objAbs as DataItem)]; } else if ( objAbs.topic == "storage" ) { res = [StorageFormsWidget(item: objAbs as StorageItem)]; + } else if ( objAbs.topic == "compute" ) { + res = [ComputeFormsWidget(item: objAbs as ComputeItem)]; } return [ Wrap( alignment: WrapAlignment.center, @@ -77,6 +82,43 @@ final WorflowService _service = WorflowService(); ]) ]; } + Widget? getTopRight(FlowData? obj) { + var objAbs = obj as AbstractItem?; + if (objAbs == null) { return null; } + if (objAbs.topic == "compute" ) { + var compute = objAbs as ComputeItem; + if (compute.technology == 0) { + return Icon(FontAwesomeIcons.docker, size: 18); + } else if (compute.technology == 1) { + return Icon(FontAwesomeIcons.lifeRing, size: 18); + } else if (compute.technology == 2) { + return Icon(FontAwesomeIcons.cubes, size: 18); + } else if (compute.technology == 3) { + return Icon(FontAwesomeIcons.hardDrive, size: 18); + } else if (compute.technology == 4) { + return Icon(FontAwesomeIcons.v, size: 18); + } + } + return null; + } + + Widget? getBottomLeftBadge(FlowData? obj) { + var objAbs = obj as AbstractItem?; + if (objAbs == null) { return null; } + if (objAbs.topic == "processing" ) { + return Icon(FontAwesomeIcons.gear) ; + } else if (objAbs.topic == "data" ) { + return Icon(FontAwesomeIcons.file); + } else if (objAbs.topic == "storage" ) { + return Icon(FontAwesomeIcons.database); + } else if (objAbs.topic == "compute" ) { + return Icon(FontAwesomeIcons.microchip); + } else if (objAbs.topic == "workflows" ) { + return Icon(FontAwesomeIcons.diagramProject); + } + return null; + } + List getDashInfoForms() { return [ SchedulerFormsWidget(item: dash), @@ -93,8 +135,10 @@ final WorflowService _service = WorflowService(); } else { name = selected; } - await _service.get(context, dash.id ?? "").then((value) { + await _service.get(context, dash.id ?? "").then((value) async { if (value.data != null) { + await WorkspaceLocal.init(context, false); + WorkspaceLocal.changeWorkspaceByName("${value.data?.name ?? ""}_workspace"); dash.clear(); dash.deserialize(value.data!.toDashboard()); Future.delayed(const Duration(seconds: 1), () { @@ -107,10 +151,11 @@ final WorflowService _service = WorflowService(); } Future saveDash(String? id) async { - if (id == null || !dash.isOpened || !dash.shouldSave) { return; } + if (id == null || !dash.isOpened || !dash.shouldSave + || !PermsService.getPerm(Perms.WORKFLOW_EDIT)) { 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( + var compute = WorkspaceLocal.byTopic("compute", 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) ); @@ -122,7 +167,7 @@ final WorflowService _service = WorflowService(); name: dash.name, graph: Graph(), data: datas.map((e) => e.id).toSet().toList(), - datacenter: dataCenter.map((e) => e.id).toSet().toList(), + compute: compute.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(), @@ -143,10 +188,11 @@ final WorflowService _service = WorflowService(); } updateW.graph?.zoom = dash.getZoomFactor(); dash.addToHistory(); - await _service.put(context, id, updateW.serialize(), {}).then( (e) { + await _service.put(context, id, updateW.serialize(), {}).then( (e) async { if (dash.addChange) { dash.addChange = false; - WorkspaceLocal.init(context, false); + await WorkspaceLocal.init(context, false); + WorkspaceLocal.changeWorkspaceByName("${dash.name}_workspace"); dash.selectedLeftMenuKey.currentState?.setState(() { }); } }); @@ -157,7 +203,7 @@ final WorflowService _service = WorflowService(); 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 == "compute") { return d as ComputeItem; } if (d.topic == "storage") { return d as StorageItem; } if (d.topic == "processing") { d = d as ProcessingItem; @@ -171,48 +217,28 @@ final WorflowService _service = WorflowService(); } Widget onDashboardMenu(Dashboard dash) { - return ShallowDropdownInputWidget( - iconLoad: Icons.share, - tooltipLoad: 'share', - tooltipRemove: 'unshare', - filled: const Color.fromRGBO(38,166, 154, 1), - color: Colors.white, - hintColor: Colors.grey.shade300, - type: SharedWorkspaceType.workflow, - all: () async => SharedWorkspaceLocal.workspaces.values.map( - (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), - current: WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared, - width: (MediaQuery.of(context).size.width / 3), - canLoad: (String? change) { - return SharedWorkspaceLocal.workspaces[change] == null - || !SharedWorkspaceLocal.workspaces[change]!.workflows.map( (e) => e.id - ).contains(dash.id); - }, - canRemove: (String? change) => SharedWorkspaceLocal.workspaces[change] == null - || SharedWorkspaceLocal.workspaces[change]!.workflows.map( (e) => e.id - ).contains(dash.id), - load: (String val) async { - await SharedService().addWorkflow(context, val, dash.id ?? ""); - SharedWorkspaceLocal.init(context, false); - dash.selectedMenuKey.currentState?.setState(() { }); - }, - remove: (String val) async { - await SharedService().removeWorkflow(context, val, dash.id ?? ""); - SharedWorkspaceLocal.init(context, false); - dash.selectedMenuKey.currentState?.setState(() { }); - }); - } - Widget menuExtension() { - var quart = MediaQuery.of(context).size.width / 6; - return ShallowDropdownInputWidget( - current: WorkspaceLocal.current, - width: quart > 80 ? quart : 80, - all: () async => WorkspaceLocal.getWorkspacesShallow(), - type: SharedWorkspaceType.workspace, - change: (String? change) { - WorkspaceLocal.changeWorkspace(change.toString()); - } - ); + return Container( padding: EdgeInsets.only(left: 50), + decoration: BoxDecoration( border: Border( left: BorderSide( color: Colors.white ))), + child: ShallowDropdownInputWidget( + filled: lightColor, + hintColor: Colors.grey.shade200, + color: Colors.white, + prefixIcon: Padding( padding: EdgeInsets.only(right: 10), child: Icon(Icons.shopping_cart, color: Colors.grey.shade200)), + current: WorkspaceLocal.current, + width: 300, + all: () async => WorkspaceLocal.getWorkspacesShallow(), + type: CollaborativeAreaType.workspace, + change: (String? change) { + WorkspaceLocal.changeWorkspace(change.toString()); + }, + canLoad: (p0) => true, + load: (p0) async { + dash.isInfo = !dash.isInfo; + dash.flutterChartKey.currentState?.setState(() { }); + }, + tooltipLoad: "open workspace manager", + iconLoad: dash.isInfo ? Icons.remove_red_eye_outlined : Icons.remove_red_eye, + )); } Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) { return ShallowCreationDialogWidget( @@ -221,28 +247,28 @@ final WorflowService _service = WorflowService(); load: (p0) async { dash.isOpened = true; if (dash.load != null) { - WorkspaceLocal.changeWorkspaceByName(p0.split("~")[1]); + WorkspaceLocal.changeWorkspaceByName(p0.split("~")[1]); await dash.load!(p0); } dash.notifyListeners(); }, - create: (p0) async => await _service.post(context, p0, {}).then( (value) { + create: PermsService.getPerm(Perms.WORKFLOW_CREATE) ? (p0) async => await _service.post(context, p0, {}).then( (value) async { dash.clear(); dash.id = value.data?.getID() ?? ""; dash.name = value.data?.getName() ?? ""; dash.notifyListeners(); - WorkspaceLocal.init(context, true); + await WorkspaceLocal.init(context, true); dash.isOpened = true; Future.delayed(const Duration(seconds: 1), () { dash.load!("${dash.id}~${dash.name}"); }); } - ), + ) : null, maptoDropdown: (e) => DropdownMenuItem( value: "${e.id}~${e.name}", child: Text(e.name), ), - type: SharedWorkspaceType.workflow, + type: CollaborativeAreaType.workflow, all: () async { List res = []; await _service.all(context).then( @@ -259,24 +285,28 @@ final WorflowService _service = WorflowService(); @override Widget build(BuildContext context) { dash.load = loadDash; dash.save = saveDash; + dash.dashColor = lightColor; + dash.midDashColor = midColor; dash.transformToData = transformToData; dash.infoItemWidget = getForms; dash.infoWidget = getDashInfoForms; - var quart = MediaQuery.of(context).size.width / 6; + dash.widthOffset = 50; return FlowChart( + key: dash.flutterChartKey, + itemLeftBottomBadges: getBottomLeftBadge, + itemrightTopBadges: getTopRight, onDashboardAlertOpened: onDashboardAlertOpened, dashboard: dash, current: widget.id, itemWidget: itemBuild, menuWidget: onDashboardMenu, - categories: const ["processing", "data", "datacenter", "storage", "workflows"], + categories: const ["processing", "data", "compute", "storage", "workflows"], draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, false), itemWidgetTooltip: itemTooltipBuild, - innerMenuWidth: quart > 80 ? quart : 80, - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height - HeaderConstants.height, + innerMenuWidth: 350, + width: getMainWidth(context), + height: getMainHeight(context), onNewConnection: (p1, p2) { }, - menuExtension: menuExtension, onDashboardTapped: (context, position) { }, onScaleUpdate: (newScale) { }, onDashboardSecondaryTapped: (context, position) { }, diff --git a/lib/widgets/catalog.dart b/lib/widgets/catalog.dart index 6de4892..456d6d2 100644 --- a/lib/widgets/catalog.dart +++ b/lib/widgets/catalog.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:oc_front/core/models/workspace_local.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/widgets/items/item_row.dart'; @@ -15,7 +16,7 @@ class CatalogWidgetState extends State { var items = widget.items ?? WorkspaceLocal.items; List itemRows = items.map((e) => ItemRowWidget( readOnly: widget.readOnly, - contextWidth: widget.itemWidth ?? MediaQuery.of(context).size.width, item: e)).toList(); + contextWidth: widget.itemWidth ?? getMainWidth(context), item: e)).toList(); return Column( children: itemRows); } } \ No newline at end of file diff --git a/lib/widgets/dialog/alert.dart b/lib/widgets/dialog/alert.dart index 2b6a398..97e3c36 100644 --- a/lib/widgets/dialog/alert.dart +++ b/lib/widgets/dialog/alert.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/main.dart'; class InfoAlertBannerChild extends StatelessWidget { final String text; @@ -9,7 +10,7 @@ class InfoAlertBannerChild extends StatelessWidget { Widget build(BuildContext context) { return Container( width: double.infinity, - constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.8), + constraints: BoxConstraints(maxWidth: getMainWidth(context) * 0.8), decoration: const BoxDecoration( color: Colors.greenAccent, borderRadius: BorderRadius.all(Radius.circular(5)), @@ -38,9 +39,9 @@ class AlertAlertBannerChild extends StatelessWidget { Widget build(BuildContext context) { return Container( width: double.infinity, - constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.8), - decoration: const BoxDecoration( - color: Colors.redAccent, + constraints: BoxConstraints(maxWidth: getMainWidth(context) * 0.8), + decoration: BoxDecoration( + color: redColor, borderRadius: BorderRadius.all( Radius.circular(5), ), diff --git a/lib/widgets/dialog/login.dart b/lib/widgets/dialog/login.dart index be1ce72..11dd4c1 100644 --- a/lib/widgets/dialog/login.dart +++ b/lib/widgets/dialog/login.dart @@ -1,74 +1,105 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:go_router/go_router.dart'; +import 'package:oc_front/core/services/auth.service.dart'; +import 'package:oc_front/main.dart'; class LoginWidget extends StatefulWidget { LoginWidget ({ Key? key }): super(key: key); @override LoginWidgetState createState() => LoginWidgetState(); } class LoginWidgetState extends State { + TextEditingController usernameCtrl = TextEditingController(); + TextEditingController passwordCtrl = TextEditingController(); + + String? error; + bool loading = false; + @override Widget build(BuildContext context) { - return AlertDialog( - backgroundColor: Colors.white, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(0))), - content: Padding(padding: const EdgeInsets.all(20), child: Column(mainAxisSize: MainAxisSize.min, children: [ - const Center(child: Padding( padding: EdgeInsets.only(bottom: 10), - child: Icon(Icons.person_search, size: 80, color: Colors.grey,))), - const Center(child: Text("WELCOME ON OPENCLOUD", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, - color: Color.fromRGBO(38, 166, 154, 1)),)), - Container( - padding: const EdgeInsets.symmetric(vertical: 20), - decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black))), - ), + return Padding(padding: const EdgeInsets.all(50), child: Column(mainAxisSize: MainAxisSize.min, children: [ + const Center(child: Icon(Icons.person_search, size: 150, color: Colors.grey,)), + Center(child: Padding( padding: const EdgeInsets.only(top: 5, bottom: 20), + child: Text("WELCOME ON OPENCLOUD", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, + color: lightColor ) ))), Container( margin: const EdgeInsets.only(bottom: 10), child: Center(child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - width: MediaQuery.of(context).size.width / 3, + width: getMainWidth(context) / 3, alignment : Alignment.center, child: TextField( + controller: usernameCtrl, + onChanged: (v) => setState(() {}), decoration: InputDecoration( - enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero), - border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero), - focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero), + border: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero), + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero), hintText: "username...", contentPadding: const EdgeInsets.symmetric(horizontal: 20), - fillColor: Colors.grey.shade300, + fillColor: midColor, filled: true, hintStyle: const TextStyle(fontSize: 12.5, color: Colors.grey)), - style: const TextStyle(fontSize: 12.5, color: Colors.grey)),), + style: const TextStyle(fontSize: 12.5, color: Colors.black)),), Container(width: 50, height: 50, color: Colors.black, child: const Icon(Icons.person, color: Colors.white)) ]))), - Container( margin: const EdgeInsets.only(bottom: 20), child: Center(child: Row( mainAxisAlignment: MainAxisAlignment.center, + Center(child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - width: MediaQuery.of(context).size.width / 3, + width: getMainWidth(context) / 3, alignment : Alignment.center, child: TextField( + controller: passwordCtrl, obscureText: true, + onChanged: (value) { + setState(() {}); + }, decoration: InputDecoration( - focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero), - enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero), - border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey.shade300), borderRadius: BorderRadius.zero), + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero), + border: OutlineInputBorder(borderSide: BorderSide(color: midColor), borderRadius: BorderRadius.zero), hintText: "password...", contentPadding: const EdgeInsets.symmetric(horizontal: 20), - fillColor: Colors.grey.shade300, + fillColor: midColor, filled: true, hintStyle: const TextStyle(fontSize: 12.5, color: Colors.grey)), - style: const TextStyle(fontSize: 12.5, color: Colors.grey)),), + style: const TextStyle(fontSize: 12.5, color: Colors.black)),), Container(width: 50, height: 50, color: Colors.black, child: const Icon(Icons.password, color: Colors.white)) - ]))), - Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Padding( padding: const EdgeInsets.only(right: 10), child: - InkWell(onTap: () { context.pop(); }, - mouseCursor: SystemMouseCursors.click, - child: Container( - margin: const EdgeInsets.only(top: 20), - width: MediaQuery.of(context).size.width / 3, - padding: const EdgeInsets.symmetric(vertical: 20), - color: const Color.fromRGBO(38, 166, 154, 1), - child: const Center( child: Text("LOGIN", style: TextStyle(color: Colors.white, fontSize: 15),))))), - ]) - ],))); + ])), + Column( children: [ + Center( child: Padding( padding: EdgeInsets.only(bottom: 10, top: error == null ? 27 : 10), child: + error == null ? Container() : Text(error ?? "", style: TextStyle(color: redColor, fontSize: 12.5)))), + Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + Padding( padding: const EdgeInsets.only(right: 10, bottom: 30), child: + InkWell(onTap: () async { + if (usernameCtrl.text == "" || passwordCtrl.text == "") { return; } + error = null; + setState(() { + loading = true; + }); + await AuthService.login(usernameCtrl.text, passwordCtrl.text).catchError( (e) { + setState(() { + loading = false; + error = "Invalid username or password"; + }); + }); + + if (error == null) { + // ignore: use_build_context_synchronously + setState(() { + loading = true; + }); + context.pop(); + } + }, + mouseCursor: SystemMouseCursors.click, + child: Container( + width: getMainWidth(context) / 3, + padding: const EdgeInsets.symmetric(vertical: 20), + color: usernameCtrl.text == "" || passwordCtrl.text == "" ? Colors.grey : lightColor, + child: Center( child: loading ? SpinKitWave(color: Colors.white, size: 20) : Text("LOGIN", style: TextStyle( + color: usernameCtrl.text == "" || passwordCtrl.text == "" ? midColor :Colors.white, + fontSize: 15) ))))), + ]) + ]), + ],)); } } \ No newline at end of file diff --git a/lib/widgets/dialog/shallow_creation.dart b/lib/widgets/dialog/shallow_creation.dart index 3c0ae8c..d8d8220 100644 --- a/lib/widgets/dialog/shallow_creation.dart +++ b/lib/widgets/dialog/shallow_creation.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/response.dart'; import 'package:oc_front/core/services/router.dart'; import 'package:oc_front/pages/shared.dart'; @@ -9,7 +10,7 @@ class ShallowCreationDialogWidget extends StatefulWidget { GlobalKey? formKey; BuildContext context; bool Function()? canClose; - SharedWorkspaceType type = SharedWorkspaceType.workspace; + CollaborativeAreaType type = CollaborativeAreaType.workspace; Future> Function()? all; Future Function(String)? load; Future Function(Map)? create; @@ -25,7 +26,7 @@ class ShallowCreationDialogState extends State { GlobalKey key = GlobalKey(); GlobalKey key2 = GlobalKey(); @override Widget build(BuildContext context) { - var t = widget.type == SharedWorkspaceType.workspace ? "workspace" : (widget.type == SharedWorkspaceType.workflow ? "workflow" : (widget.type == SharedWorkspaceType.shared_workspace ? "shared workspace" :"peer")); + var t = widget.type == CollaborativeAreaType.workspace ? "workspace" : (widget.type == CollaborativeAreaType.workflow ? "workflow" : (widget.type == CollaborativeAreaType.collaborative_area ? "collaborative area" :"peer")); return Container( color: Colors.white, padding: const EdgeInsets.only( top: 0, bottom: 20, left: 20, right: 20), @@ -57,7 +58,8 @@ class ShallowCreationDialogState extends State { ShallowDropdownInputWidget( all: widget.all, type: widget.type, - width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, + hint: "select a $t", + width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400, load: (e) async { await widget.load!(e); Navigator.pop(widget.context); @@ -71,13 +73,14 @@ class ShallowCreationDialogState extends State { deletion: true, color: Colors.black, hintColor: Colors.grey, - filled: Colors.grey.shade300, + filled: midColor, ), Container( height: 10), - ShallowTextInputWidget( + widget.create != null ? ShallowTextInputWidget( key: widget.formKey, type: widget.type, - width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, + hint: "create a new $t", + width: getMainWidth(context) <= 540 ? getMainWidth(context) - 140 : 400, load: (e) async { await widget.create!(e); Navigator.pop(widget.context); @@ -86,9 +89,9 @@ class ShallowCreationDialogState extends State { canLoad: (p0) => p0 != null && p0.isNotEmpty, color: Colors.black, hintColor: Colors.grey, - filled: Colors.grey.shade300, - ), - ...widget.form.map( (e) => Container( margin: const EdgeInsets.only(top: 10), child: e)), + filled: midColor, + ) : Container(), + ...(widget.create != null ? widget.form.map( (e) => Container( margin: const EdgeInsets.only(top: 10), child: e)) : []), ] ) ); diff --git a/lib/widgets/forms/compute_forms.dart b/lib/widgets/forms/compute_forms.dart new file mode 100644 index 0000000..d9f7c4b --- /dev/null +++ b/lib/widgets/forms/compute_forms.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:oc_front/widgets/inputs/sub_text_input.dart'; + +class ComputeFormsWidget extends StatefulWidget { + dynamic item; + ComputeFormsWidget ({ super.key, required this.item }); + @override ComputeFormsWidgetState createState() => ComputeFormsWidgetState(); +} +class ComputeFormsWidgetState extends State { + @override Widget build(BuildContext context) { + return Column( children: [ + SubTextInputWidget(subkey: "technology", width: 180, empty: false, change: (value) { + }, initialValue: widget.item.getTechnology(), readOnly: true,), + SubTextInputWidget(subkey: "architecture", width: 180, empty: false, change: (value) { + }, initialValue: widget.item.architecture, readOnly: true,), + SubTextInputWidget(subkey: "access", width: 180, empty: false, change: (value) { + }, initialValue: widget.item.getAccess(), readOnly: true,), + SubTextInputWidget(subkey: "localisation", width: 180, empty: false, change: (value) { + }, initialValue: widget.item.localisation, readOnly: true,), + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/forms/data_forms.dart b/lib/widgets/forms/data_forms.dart index 3714bac..99c2af5 100644 --- a/lib/widgets/forms/data_forms.dart +++ b/lib/widgets/forms/data_forms.dart @@ -11,7 +11,6 @@ class DataFormsWidget extends StatefulWidget { } class DataFormsWidgetState extends State { @override Widget build(BuildContext context) { - print(widget.item.serialize()); return Column( children: [ WebReferenceFormsWidget(item: widget.item), ]); diff --git a/lib/widgets/forms/processing_forms.dart b/lib/widgets/forms/processing_forms.dart index c0fc3a1..addc194 100644 --- a/lib/widgets/forms/processing_forms.dart +++ b/lib/widgets/forms/processing_forms.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart'; +import 'package:oc_front/core/services/perms_service.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/workflow.dart'; @@ -18,7 +20,7 @@ class ProcessingFormsWidget extends StatefulWidget { @override ProcessingFormsWidgetState createState() => ProcessingFormsWidgetState(); } class ProcessingFormsWidgetState extends State { - Widget getInputAndOutputVariableForms() { + Widget getInputAndOutputVariableForms(bool readOnly) { var inList = widget.dash.GetArrowByElementID(widget.elementID, true); var outList = widget.dash.GetArrowByElementID(widget.elementID, false); List res = []; @@ -40,16 +42,17 @@ class ProcessingFormsWidgetState extends State { } if (inItems.isNotEmpty) { res.add(SubKeysMapFormsWidget(dash: widget.dash, isInput: true, item: widget.item, elementID: widget.elementID, - categoryKey: "container", varKey: "env", graphItems: inItems)); + categoryKey: "container", varKey: "env", graphItems: inItems, readOnly: readOnly)); } if (outItems.isNotEmpty) { res.add(SubKeysMapFormsWidget(dash: widget.dash, isInput: false, item: widget.item, elementID: widget.elementID, - categoryKey: "container", varKey: "env", graphItems: outItems)); + categoryKey: "container", varKey: "env", graphItems: outItems, readOnly: readOnly)); } return Column( children: res ); } @override Widget build(BuildContext context) { + bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT); List categories = []; var l = widget.item.model?.model?.keys ?? []; for (var child in l) { @@ -59,11 +62,14 @@ class ProcessingFormsWidgetState extends State { if (sub[st]!.type?.contains("map") ?? false) { children.add( SubMapFormsWidget(dash: dash, empty: children.isEmpty, item: widget.item, + readOnly: readOnly, elementID: widget.elementID, categoryKey: child, varKey: st) ); } else if (sub[st]!.type == "string") { - children.add(SubTextInputWidget(subkey: st, initialValue: widget.item.getVariable([child, st], widget.item.serialize()), - width: 200, empty: children.isEmpty, change: (value) { + children.add(SubTextInputWidget(subkey: st, + readOnly: readOnly, + initialValue: widget.item.getVariable([child, st], widget.item.serialize()), + width: 180, empty: children.isEmpty, change: (value) { widget.item.model ?? Model(); Future.delayed(const Duration(seconds: 2), () { if (widget.item.getVariable([child, st], widget.item.serialize()) == value) { @@ -78,41 +84,40 @@ class ProcessingFormsWidgetState extends State { } } categories.add(Container( - padding: const EdgeInsets.all(10), - width: 250, + padding: const EdgeInsets.symmetric(vertical: 10), + width: 180, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("<${child.toUpperCase()}>", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center), - Padding(padding: const EdgeInsets.only(bottom: 10), child: SubTextInputWidget(subkey: "image", width: 200, empty: false, change: (value) {}, + Padding(padding: const EdgeInsets.only(bottom: 10), child: SubTextInputWidget(subkey: "image", width: 180, empty: false, change: (value) {}, initialValue: widget.item.container?.image, readOnly: true,)), ...children, - getInputAndOutputVariableForms(), + getInputAndOutputVariableForms(readOnly), ],) )); } // EXPOSE categories.add(Container( - padding: const EdgeInsets.all(10), - width: 250, - decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.grey, width: 1))), + padding: const EdgeInsets.symmetric(vertical: 10), + width: 180, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Padding(padding: EdgeInsets.only(bottom: 5), child: Text("", style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center)), - Row( children: [ + readOnly ? Container() : Row( children: [ InkWell( onTap: () { widget.item.expose.add(Expose()); var el = dash.getElement(widget.elementID); el!.element = widget.item as dynamic; setState(() {}); }, child: - Container( margin: const EdgeInsets.only(left: 15, top: 5), + Container( margin: const EdgeInsets.only(top: 5), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), - width: 150, height: 30, + width: 125, height: 30, child: const Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add)), Text("add exposure")]), + children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add)), Text("add expose")]), ) ), InkWell( onTap: () { @@ -122,7 +127,7 @@ class ProcessingFormsWidgetState extends State { el!.element = widget.item as dynamic; setState(() {}); }, child: - Container( margin: const EdgeInsets.only(left: 5, right: 10, top: 5), + Container( margin: const EdgeInsets.only(left: 5, top: 5), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), width: 45, height: 30, child: const Row( mainAxisAlignment: MainAxisAlignment.center, @@ -133,10 +138,10 @@ class ProcessingFormsWidgetState extends State { ],) )); for (var expose in widget.item.expose) { - categories.add(SubExposeFormsWidget( width: 200, dash: dash, empty: categories.isEmpty, + categories.add(SubExposeFormsWidget( readOnly: readOnly, width: 180, dash: dash, empty: categories.isEmpty, item: expose, elementID: widget.elementID)); } - return SizedBox( height: MediaQuery.of(context).size.height - 330, child: SingleChildScrollView( child: Column( + return SizedBox( height: getHeight(context) - 330, child: SingleChildScrollView( child: Column( children: categories )) ); } } \ No newline at end of file diff --git a/lib/widgets/forms/scheduler_forms.dart b/lib/widgets/forms/scheduler_forms.dart index feff82c..411dcac 100644 --- a/lib/widgets/forms/scheduler_forms.dart +++ b/lib/widgets/forms/scheduler_forms.dart @@ -3,12 +3,12 @@ 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'; import 'package:oc_front/core/models/shared_workspace_local.dart'; +import 'package:oc_front/core/services/perms_service.dart'; import 'package:oc_front/core/services/specialized_services/workflow_service.dart'; - import 'package:oc_front/core/services/specialized_services/check_service.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/pages/shared.dart'; import 'package:oc_front/pages/workflow.dart'; import 'package:oc_front/widgets/dialog/alert.dart'; @@ -18,6 +18,9 @@ class SchedulerFormsWidget extends StatefulWidget { Dashboard item; String purpose = ""; bool? booking; + String? error; + String? errorEndDate; + String? errorCron; Function validate = () {}; SchedulerFormsWidget ({ super.key, required this.item, }); @override SchedulerFormsWidgetState createState() => SchedulerFormsWidgetState(); @@ -26,9 +29,12 @@ class SchedulerFormsWidgetState extends State { CheckService check = CheckService(); void save(List> formKeys) { dash.scheduleActive = !dash.scheduleActive; + widget.error = null; + widget.errorEndDate = null; + widget.errorCron = null; for (var k in formKeys) { if (k.currentState != null) { - if (!k.currentState!.validate()) { + if (!k.currentState!.validate() && dash.scheduleActive) { dash.scheduleActive = !dash.scheduleActive; return; } else { k.currentState!.save();} @@ -41,7 +47,6 @@ class SchedulerFormsWidgetState extends State { dash.scheduler["end"] = now.add(const Duration(minutes: 1)).toUtc().toIso8601String(); } } - print(widget.item.id); widget.item.save!(widget.item.id); } void checkBooking(List> formKeys, void Function(List> )? f){ @@ -60,9 +65,7 @@ class SchedulerFormsWidgetState extends State { (v) { if (v.data == null) { return; } widget.booking = v.data!.is_available; - print(v.data!.is_available); if (v.data!.is_available) { - print(f); if (f != null) { f(formKeys); } else { showAlertBanner( context, () {}, @@ -80,11 +83,13 @@ class SchedulerFormsWidgetState extends State { } @override Widget build(BuildContext context) { + bool isService = true; try { - if (widget.item.scheduler["mode"] == null) { widget.item.scheduler["mode"] = 1; } + widget.item.elements.firstWhere((element) => (element.element?.serialize()["is_service"] ?? false) == true); } catch (e) { - widget.item.scheduler = { "mode": 1 }; + isService = false; } + bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT); DateTime? start; DateTime? end; if (widget.item.scheduler["start"] != null) { @@ -101,14 +106,13 @@ class SchedulerFormsWidgetState extends State { widget.item.scheduler["end"] = end.toUtc().toIso8601String(); } } - List> formKeys = [GlobalKey(), GlobalKey(), - GlobalKey(), GlobalKey()]; + List> formKeys = [GlobalKey(), GlobalKey(), GlobalKey(), GlobalKey()]; var shallow = ShallowTextInputWidget( - width: 250 - 1, + width: 200 - 1, readOnly: readOnly, current: widget.item.name, - type: SharedWorkspaceType.workflow, - canRemove: (p0) => p0 != null && p0.isNotEmpty, - remove: (p0) async { + type: CollaborativeAreaType.workflow, + canRemove: PermsService.getPerm(Perms.WORKFLOW_DELETE) ? (p0) => p0 != null && p0.isNotEmpty : null, + remove: PermsService.getPerm(Perms.WORKFLOW_DELETE) ? (p0) async { await WorflowService().delete(context, widget.item.id ?? "", {}).then((value) { dash.id = null; dash.name = ""; @@ -116,7 +120,7 @@ class SchedulerFormsWidgetState extends State { dash.clear(); dash.chartKey.currentState?.widget.flowChart.setState(() { }); }); - }, + } : null, ); shallow.change =(p0) => Future.delayed( const Duration(seconds: 2), () async { if (shallow.compare == p0) { @@ -126,7 +130,7 @@ class SchedulerFormsWidgetState extends State { } }); return Column( children: [ - Container( padding: const EdgeInsets.all(10), width: 250, height: 60, + 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), @@ -134,32 +138,17 @@ class SchedulerFormsWidgetState extends State { ])), widget.item.name == "" ? Container() : Container( decoration: BoxDecoration( border: Border( - left: BorderSide(color: Colors.grey.shade300, width: 1), + left: BorderSide(color: midColor, width: 1), bottom: const BorderSide(color: Colors.grey))), child: shallow ), - const SizedBox(height: 20, width: 250 ), - AdvancedSwitch( - width: 140, - initialValue: widget.item.scheduler["mode"] == 1, - activeColor: Colors.green, inactiveColor: Colors.green, - activeChild: const Text("simple task", 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.scheduler["mode"] = value == true ? 1 : 0; - if ((widget.item.scheduler["mode"] == 1 )) { widget.item.scheduler.remove("cron"); } - widget.item.save!(widget.item.id); - })); - },), - Container(height: 5), - Tooltip( message: "event name", + const SizedBox(height: 20, width: 200 ), + isService ? Text("Warning a processing is a service, if no end execution it will run forever.") : Container(), + Tooltip( message: "executions 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.scheduler["mode"] == 1 ? "" : "cron_"}${widget.item.scheduler["name"] ?? "${widget.item.name}_event"}", - enabled: !dash.scheduleActive, + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + child: TextFormField( key: formKeys[0], readOnly: readOnly, + initialValue: "${widget.item.scheduler["name"] ?? "${widget.item.name}_executions"}", + enabled: !dash.scheduleActive && !readOnly, onChanged: (value) { Future.delayed(const Duration(seconds: 100), () { if (widget.item.scheduler["name"] == value) { @@ -169,30 +158,36 @@ class SchedulerFormsWidgetState extends State { widget.item.scheduler["name"] = value; }, onSaved: (value) { - widget.item.scheduler["name"] = value ?? "${widget.item.scheduler["mode"] == 1 ? "" : "cron_"}${widget.item.scheduler["name"] ?? "${widget.item.name}_event"}"; + widget.item.scheduler["name"] = value ?? "${widget.item.scheduler["name"] ?? "${widget.item.name}_executions"}"; + }, + validator: (value) { + if (value == null || value.isEmpty) { + setState(() { widget.error = 'missing name'; }); + } + return value == null || value.isEmpty ? "not empty" : null; }, - validator: (value) => value == null || value.isEmpty ? "not empty" : null, style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( + decoration: InputDecoration( floatingLabelBehavior: FloatingLabelBehavior.always, fillColor: Colors.white, filled: true, - hintText: "enter event name...", - labelText: "event name*", - errorStyle: TextStyle(fontSize: 0), + hintText: "enter executions name...", + labelText: "executions name*", hintStyle: TextStyle(fontSize: 10), labelStyle: TextStyle(fontSize: 10), - error: null, - enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), - border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.black)), + errorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.black)), + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.black)), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.grey)), + border: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.grey)), contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), ), ))), - Tooltip( message: "start event", + Tooltip( message: "start executions", child: Container( height: 40, margin: const EdgeInsets.only(top: 5), - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), child: DateTimeField( key: formKeys[1], - enabled: !dash.scheduleActive, + enabled: !dash.scheduleActive && !readOnly, resetIcon: null, onShowPicker: (context, currentValue) async { var date = await showDatePicker( @@ -202,7 +197,7 @@ class SchedulerFormsWidgetState extends State { 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, + background: midColor, tertiary: Colors.grey, secondary: Colors.grey, primary: Colors.black), @@ -236,7 +231,7 @@ class SchedulerFormsWidgetState extends State { 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, + background: midColor, tertiary: Colors.grey, secondary: Colors.grey, primary: Colors.black), @@ -258,16 +253,17 @@ class SchedulerFormsWidgetState extends State { format: intl.DateFormat('y-M-dd HH:mm:ss'), initialValue: start?.toLocal() ?? DateTime.now(), onChanged: (value) { }, - validator: (value) => value == null ? "not empty" : null, + validator: (value) { + return value == null ? "not empty" : null; + }, style: const TextStyle(fontSize: 12), decoration: const InputDecoration( floatingLabelBehavior: FloatingLabelBehavior.always, fillColor: Colors.white, filled: true, alignLabelWithHint: false, - hintText: "enter start event...", - labelText: "start event*", - errorStyle: TextStyle(fontSize: 0), + hintText: "enter start executions...", + labelText: "start executions*", hintStyle: TextStyle(fontSize: 10), labelStyle: TextStyle(fontSize: 10), enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), @@ -275,13 +271,18 @@ class SchedulerFormsWidgetState extends State { contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), ), ))), - Tooltip( message: "end event", + Tooltip( message: "end executions", child: Container( height: 40, margin: const EdgeInsets.only(top: 5), - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), child: DateTimeField( key: formKeys[2], - enabled: !dash.scheduleActive, + enabled: !dash.scheduleActive && !readOnly, validator: (value) { - return value == null && !(widget.item.scheduler["mode"] == 1 ) ? "not empty" : null; + if (value == null && widget.item.scheduler["cron"] != null && widget.item.scheduler["cron"].isNotEmpty) { + setState(() { + widget.errorEndDate = 'missing start date'; + }); + } + return value == null && widget.item.scheduler["cron"] != null && widget.item.scheduler["cron"].isNotEmpty ? "not empty" : null; }, onChanged: (value) { if (value == null) { @@ -297,7 +298,7 @@ class SchedulerFormsWidgetState extends State { 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, + background: midColor, tertiary: Colors.grey, secondary: Colors.grey, primary: Colors.black), @@ -321,11 +322,12 @@ class SchedulerFormsWidgetState extends State { while(date!.microsecondsSinceEpoch <= (DateTime.now().microsecondsSinceEpoch) || time == null || (date.microsecondsSinceEpoch) <= (DateTime.parse(widget.item.scheduler["start"] ?? DateTime.now().toIso8601String()).microsecondsSinceEpoch)) { - if (count > 0) { - showAlertBanner( context, () {}, + if (count > 0) { + showAlertBanner( context, () {}, // ignore: use_build_context_synchronously const AlertAlertBannerChild(text: "must be at least 1 minute from now to let system check info && upper starting date"),// <-- Put any widget here you want! alertBannerLocation: AlertBannerLocation.bottom,); } + // ignore: use_build_context_synchronously time = await showTimePicker(context: context, initialTime: TimeOfDay(hour: date.hour, minute: date.minute), builder: (BuildContext context, Widget? child) { @@ -334,7 +336,7 @@ class SchedulerFormsWidgetState extends State { 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, + background: midColor, tertiary: Colors.grey, secondary: Colors.grey, primary: Colors.black), @@ -361,21 +363,23 @@ class SchedulerFormsWidgetState extends State { floatingLabelBehavior: FloatingLabelBehavior.always, filled: true, alignLabelWithHint: false, - hintText: "enter end event...", - labelText: "end event${!(widget.item.scheduler["mode"] == 1) ? "*" : ""}", - errorStyle: const TextStyle(fontSize: 0), + hintText: "enter end executions...", + labelText: "end executions", 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)), + focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.black)), + errorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.black)), + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.black)), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.grey)), + border: OutlineInputBorder(borderSide: BorderSide(color: widget.errorEndDate != null ? Colors.red : Colors.grey)), contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), ), ))), - widget.item.scheduler["mode"] == 1 ? Container() : Tooltip( message: "schedule", + Tooltip( message: "cron command", child: Container( height: 40, margin: const EdgeInsets.only(top: 5), - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), child: TextFormField( key: formKeys[3], - enabled: !dash.scheduleActive, + enabled: !dash.scheduleActive && !readOnly, initialValue: widget.item.scheduler["cron"], onChanged: (value) { Future.delayed(const Duration(seconds: 100), () { @@ -392,58 +396,67 @@ class SchedulerFormsWidgetState extends State { }, validator: (value) { var cron = Cron(); - try { - cron.schedule(Schedule.parse(value ?? ""), () {}); - } catch (e) { - return "invalid cron"; + if (value != null && value.isNotEmpty) { + try { + cron.schedule(Schedule.parse(value), () {}); + } catch (e) { + setState(() { + widget.errorCron = e.toString(); + }); + return "invalid cron"; + } } - return value == null || value.isEmpty ? "not empty" : null; + return null; }, style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( + decoration: InputDecoration( floatingLabelBehavior: FloatingLabelBehavior.always, fillColor: Colors.white, filled: true, - hintText: "enter schedule...", - labelText: "schedule*", - errorStyle: TextStyle(fontSize: 0), + hintText: "enter cron command...", + labelText: "cron", + errorStyle: TextStyle(height: 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)), + focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.black)), + errorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.black)), + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.black)), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.grey)), + border: OutlineInputBorder(borderSide: BorderSide(color: widget.errorCron != null ? Colors.red : Colors.grey)), contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), ), ))), Container( - width: 250, + width: 200, height: 20, decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), ), const SizedBox( - width: 250, + width: 200, height: 10, ), Tooltip( message: "check booking", child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { - checkBooking(formKeys, null); - }, child: Container( margin: const EdgeInsets.only(bottom: 5), + PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? checkBooking(formKeys, null) : null; + }, child: Container( margin: const EdgeInsets.only(bottom: 5, left: 10, right: 10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), - border: Border.all(color: widget.booking == null && !dash.scheduleActive ? Colors.black : (widget.booking == true || dash.scheduleActive ? Colors.green : Colors.red), width: 1)), + border: Border.all(color: widget.booking == null && !dash.scheduleActive ? ( + PermsService.getPerm(Perms.WORKFLOW_BOOKING) && PermsService.getPerm(Perms.WORKFLOW_EDIT) ? Colors.black : Colors.grey) : ( + widget.booking == true || dash.scheduleActive ? Colors.green : redColor), width: 1)), width: 200, height: 30, child: Icon( Icons.verified_outlined, - color: widget.booking == null && !dash.scheduleActive ? Colors.black : (widget.booking == true || dash.scheduleActive ? Colors.green : Colors.red)), + color: widget.booking == null && !dash.scheduleActive ? Colors.black : (widget.booking == true || dash.scheduleActive ? Colors.green : redColor)), )) ), Tooltip( message: dash.scheduleActive ? "unbook" : "book", child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { - dash.scheduleActive ? setState(() { save(formKeys); }) : checkBooking(formKeys, save); + PermsService.getPerm(Perms.WORKFLOW_BOOKING) && PermsService.getPerm(Perms.WORKFLOW_EDIT) ? (dash.scheduleActive ? setState(() { save(formKeys); }) : checkBooking(formKeys, save)) : null; }, child: Container( margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), - border: Border.all(color: dash.scheduleActive ? Colors.green : Colors.black)), + border: Border.all(color: dash.scheduleActive ? Colors.green : ( PermsService.getPerm(Perms.WORKFLOW_BOOKING) ?Colors.black : Colors.grey ))), width: 200, height: 30, child: Icon( dash.scheduleActive ? Icons.cancel_schedule_send : Icons.schedule_send, color: dash.scheduleActive ? Colors.green : Colors.black), @@ -452,17 +465,17 @@ class SchedulerFormsWidgetState extends State { widget.item.info["shared"] != null && (widget.item.info["shared"] as List).isNotEmpty ? Column( children: [ Container( height: 20, - width: 250, + width: 200, decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.black))), ), - Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 20), + Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10), child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold), "Workflow is shared in ${(widget.item.info["shared"] as List).length} workspace(s)")), - ...(widget.item.info["shared"] as List).where( (e) => SharedWorkspaceLocal.getSharedWorkspace(e) != null + ...(widget.item.info["shared"] as List).where( (e) => CollaborativeAreaLocal.getCollaborativeArea(e) != null ).map((e) { - var sw = SharedWorkspaceLocal.getSharedWorkspace(e); - return Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), + var sw = CollaborativeAreaLocal.getCollaborativeArea(e); + return Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Row( children: [ const Padding(padding: EdgeInsets.only(right: 10), child: Icon(Icons.work, color: Colors.grey, size: 15)), Text(style: const TextStyle(fontSize: 12, color: Colors.grey), diff --git a/lib/widgets/forms/sub_expose_forms.dart b/lib/widgets/forms/sub_expose_forms.dart index 694d425..c7f23c5 100644 --- a/lib/widgets/forms/sub_expose_forms.dart +++ b/lib/widgets/forms/sub_expose_forms.dart @@ -5,12 +5,13 @@ import 'package:oc_front/models/search.dart'; import 'package:oc_front/widgets/inputs/sub_text_input.dart'; class SubExposeFormsWidget extends StatefulWidget { + bool readOnly; Expose item; Dashboard dash; String elementID = ""; - double width = 200; + double width = 180; bool empty = false; - SubExposeFormsWidget ({ super.key, required this.dash, + SubExposeFormsWidget ({ super.key, required this.dash, this.readOnly = false, this.empty = false, required this.item, required this.elementID, required this.width }); @override SubExposeFormsWidgetState createState() => SubExposeFormsWidgetState(); } @@ -19,9 +20,10 @@ class SubExposeFormsWidgetState extends State { return Column( children : [ Container( margin: const EdgeInsets.only(left: 10, right: 10, top: 5), decoration: BoxDecoration(border: Border.all(color: Colors.grey, width: 1)), - width: 250 + width: 180 ), - SubTextInputWidget(subkey: "reference port", initialValue: widget.item.port != null ? '${widget.item.port}' : null, + SubTextInputWidget(subkey: "reference port", readOnly: widget.readOnly, + initialValue: widget.item.port != null ? '${widget.item.port}' : null, width: widget.width, empty: widget.empty, change: (value) { try { widget.item.port = int.parse(value); @@ -34,7 +36,9 @@ class SubExposeFormsWidgetState extends State { var el = widget.dash.getElement(widget.elementID); el!.element = widget.item as dynamic; }), - SubTextInputWidget(subkey: "PAT", initialValue: widget.item.PAT != null ? '${widget.item.PAT}' : null, + SubTextInputWidget( + readOnly: widget.readOnly, + subkey: "PAT", initialValue: widget.item.PAT != null ? '${widget.item.PAT}' : null, width: widget.width, empty: widget.empty, change: (value) { try { widget.item.PAT = int.parse(value); @@ -48,6 +52,7 @@ class SubExposeFormsWidgetState extends State { el!.element = widget.item as dynamic; }), SubTextInputWidget(subkey: "reverse path", initialValue: widget.item.PAT != null ? '${widget.item.PAT}' : null, + readOnly: widget.readOnly, width: widget.width, empty: widget.empty, change: (value) { try { widget.item.path = value; diff --git a/lib/widgets/forms/sub_keys_forms.dart b/lib/widgets/forms/sub_keys_forms.dart index 89d033e..05ff15c 100644 --- a/lib/widgets/forms/sub_keys_forms.dart +++ b/lib/widgets/forms/sub_keys_forms.dart @@ -6,6 +6,7 @@ import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/widgets/inputs/sub_text_input.dart'; class SubKeysMapFormsWidget extends StatefulWidget { + bool readOnly = false; FlowData item; Dashboard dash; String varKey = ""; @@ -14,7 +15,7 @@ class SubKeysMapFormsWidget extends StatefulWidget { String elementID = ""; String categoryKey = ""; List graphItems = []; - SubKeysMapFormsWidget({ super.key, required this.dash, required this.isInput, + SubKeysMapFormsWidget({ super.key, required this.dash, required this.isInput, this.readOnly = false, this.empty = false, required this.item, required this.elementID, required this.graphItems, required this.categoryKey, required this.varKey }); @override SubKeysMapFormsWidgetState createState() => SubKeysMapFormsWidgetState(); @@ -31,7 +32,7 @@ class SubKeysMapFormsWidgetState extends State { if (el == null || el.model == null) { continue; } for ( var r in el.model!.refs.keys) { var env = widget.item.getVariable(["container", "env"], widget.item.serialize()); - if (env == null && env is Map) { continue; } + if (env == null || env is Map) { continue; } var n = "${el.topic.toUpperCase()}_${el.getName().toUpperCase().replaceAll(" ", "_")}_${r.toUpperCase()}_$count"; if (env[n] == null) { save = true; @@ -39,7 +40,8 @@ class SubKeysMapFormsWidgetState extends State { env[n]= "{{ ${ widget.isInput ? "in" : "out" }_${graphItem.id}_$r }}"; widget.item.setVariable(["container", "env"], env, el.serialize()); children.add( Padding(padding: const EdgeInsets.only(bottom: 10), - child: SubTextInputWidget(subkey: n, width: 200, empty: false, change: (value) {}, initialValue: n, readOnly: true, noLabel: true))); + child: SubTextInputWidget(subkey: n, width: 180, empty: false, change: (value) {}, + initialValue: n, readOnly: true, noLabel: true))); count++; } } @@ -50,7 +52,7 @@ class SubKeysMapFormsWidgetState extends State { return Container(); } return Column( children : [ - Container(width: 250, padding: const EdgeInsets.only(top: 10, bottom: 10), + Container(width: 200, padding: const EdgeInsets.only(top: 10, bottom: 10), decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1)))), Padding( padding: const EdgeInsets.only(top: 10), child: Text("<${widget.isInput ? "INPUT ENV VARIABLE" : "OUTPUT ENV VARIABLE"}>", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), diff --git a/lib/widgets/forms/sub_map_forms.dart b/lib/widgets/forms/sub_map_forms.dart index e05fdf8..129ca14 100644 --- a/lib/widgets/forms/sub_map_forms.dart +++ b/lib/widgets/forms/sub_map_forms.dart @@ -10,6 +10,7 @@ class MapForm { } class SubMapFormsWidget extends StatefulWidget { + bool readOnly; String categoryKey = ""; String varKey = ""; String elementID = ""; @@ -17,7 +18,7 @@ class SubMapFormsWidget extends StatefulWidget { Dashboard dash; bool empty = false; List forms = []; - SubMapFormsWidget ({ super.key, required this.dash, + SubMapFormsWidget ({ super.key, required this.dash, this.readOnly = false, this.empty = false, required this.item, required this.elementID, required this.categoryKey, required this.varKey }); @override SubMapFormsWidgetState createState() => SubMapFormsWidgetState(); @@ -44,8 +45,9 @@ class SubMapFormsWidgetState extends State { continue; } widget.forms.add(MapForm(key: key, value: m[key])); - children.add(Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: Row( children: [ - SubTextInputWidget(subkey: "key", initialValue: key, width: 91, empty: widget.empty, + children.add(Row( children: [ + SubTextInputWidget(subkey: "key", readOnly: widget.readOnly, + initialValue: key, width: 77.5, empty: widget.empty, change: (value) { setState(() { widget.forms[i].key = value; @@ -58,8 +60,8 @@ class SubMapFormsWidgetState extends State { }); }), const Padding(padding: EdgeInsets.only(left: 5, right: 5, top: 15), child: Text("=", textAlign: TextAlign.center,)), - SubTextInputWidget(subkey: "value", initialValue: widget.forms[i].value, width: 90.8, empty: widget.empty, - change: (value) { + SubTextInputWidget(subkey: "value", initialValue: widget.forms[i].value, width: 77.5, empty: widget.empty, + readOnly: widget.readOnly, change: (value) { Future.delayed(const Duration(seconds: 2), () { widget.dash.save!(widget.dash.id); }); @@ -69,13 +71,13 @@ class SubMapFormsWidgetState extends State { widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; el!.element = widget.item as dynamic; }), - ]))); + ])); i++; } return Column( children : [ - Container(width: 250, padding: const EdgeInsets.only(top: 10), + Container(width: 200, padding: const EdgeInsets.only(top: 10), decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),), - Row( children: [ + widget.readOnly ? Container() : Row( children: [ InkWell( onTap: () { widget.forms.add(MapForm(key: "", value: "")); var el = widget.dash.getElement(widget.elementID); @@ -83,9 +85,9 @@ class SubMapFormsWidgetState extends State { widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; el!.element = widget.item as dynamic; setState(() {}); - }, child: Container( margin: const EdgeInsets.only(left: 15, top: 10), + }, child: Container( margin: const EdgeInsets.only(top: 10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), - width: 150, height: 30, + width: 125, height: 30, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add)), Text("add ${widget.varKey} vars")]), ), @@ -99,7 +101,7 @@ class SubMapFormsWidgetState extends State { el!.element = widget.item as dynamic; setState(() { widget.dash.save!(widget.dash.id); }); }, child: - Container( margin: const EdgeInsets.only(left: 5, right: 10, top: 10), + Container( margin: const EdgeInsets.only(left: 5, top: 10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), width: 45, height: 30, child: const Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/widgets/forms/web_reference_forms.dart b/lib/widgets/forms/web_reference_forms.dart index 66aff2b..6c2dfab 100644 --- a/lib/widgets/forms/web_reference_forms.dart +++ b/lib/widgets/forms/web_reference_forms.dart @@ -9,14 +9,14 @@ class WebReferenceFormsWidget extends StatefulWidget { class WebReferenceFormsWidgetState extends State { @override Widget build(BuildContext context) { return Column( children: [ - SubTextInputWidget(subkey: "path", width: 200, empty: false, change: (value) { - widget.item.protocols = value.split(","); + SubTextInputWidget(subkey: "path", width: 180, empty: false, change: (value) { + widget.item.path = value.split(","); }, initialValue: widget.item.path, readOnly: true,), - SubTextInputWidget(subkey: "protocol", width: 200, empty: false, change: (value) { - widget.item.protocols = value.split(","); + SubTextInputWidget(subkey: "protocol", width: 180, empty: false, change: (value) { + widget.item.protocol = value.split(","); }, initialValue: widget.item.protocol, readOnly: true,), - SubTextInputWidget(subkey: "type", width: 200, empty: false, change: (value) { - widget.item.protocols = value.split(","); + SubTextInputWidget(subkey: "type", width: 180, empty: false, change: (value) { + widget.item.type = value.split(","); }, initialValue: widget.item.type, readOnly: true,), ]); } diff --git a/lib/widgets/inputs/shallow_dropdown_input.dart b/lib/widgets/inputs/shallow_dropdown_input.dart index f949650..8b37ef6 100644 --- a/lib/widgets/inputs/shallow_dropdown_input.dart +++ b/lib/widgets/inputs/shallow_dropdown_input.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/response.dart'; import 'package:oc_front/pages/shared.dart'; class ShallowDropdownInputWidget extends StatefulWidget { double? width; - SharedWorkspaceType type = SharedWorkspaceType.workspace; + CollaborativeAreaType type = CollaborativeAreaType.workspace; Future> Function()? all; Future Function(String)? load; Future Function(String)? remove; @@ -13,7 +14,7 @@ class ShallowDropdownInputWidget extends StatefulWidget { void Function(String?)? change; DropdownMenuItem Function(Shallow)? maptoDropdown; String? current; - + Widget? prefixIcon; IconData? iconLoad; IconData? iconRemove; @@ -28,7 +29,7 @@ class ShallowDropdownInputWidget extends StatefulWidget { bool deletion = false; - ShallowDropdownInputWidget ({ Key? key, this.width, this.current, required this.all, + ShallowDropdownInputWidget ({ Key? key, this.width, this.current, required this.all, this.prefixIcon, this.iconLoad, this.iconRemove, this.hint, this.filled, this.hintColor, this.color, this.tooltipLoad, this.tooltipRemove, this.deletion = false, this.maptoDropdown, required this.type, this.canLoad, this.canRemove, this.load, this.remove, this.change }): super(key: key); @@ -39,7 +40,7 @@ class ShallowDropdownInputWidgetState extends State if (widget.deletion && widget.remove == null) { widget.remove =(p0) async => widget.current = null; } - var t = widget.type == SharedWorkspaceType.workspace ? "workspace" : (widget.type == SharedWorkspaceType.workflow ? "workflow" : "peer"); + var t = widget.type == CollaborativeAreaType.workspace ? "workspace" : (widget.type == CollaborativeAreaType.workflow ? "workflow" : "peer"); return FutureBuilder(future: widget.all!(), builder: (b, s) { List items = []; if (widget.maptoDropdown != null) { @@ -53,7 +54,7 @@ class ShallowDropdownInputWidgetState extends State data: Theme.of(context).copyWith( canvasColor: widget.filled ??Colors.white, ), - child: Container( height: 50, width: (widget.width ?? MediaQuery.of(context).size.width) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50), + child: Container( height: 50, width: (widget.width ?? getMainWidth(context)) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50), decoration: const BoxDecoration( color: Colors.white, ), @@ -70,13 +71,15 @@ class ShallowDropdownInputWidgetState extends State isExpanded: true, style: TextStyle(color: widget.color ?? Colors.black, fontSize: 15), hint: Text(widget.hint ?? "load $t...", - style: TextStyle(color: widget.hintColor ??Colors.grey.shade300, fontSize: 14)), + style: TextStyle(color: widget.hintColor ??midColor, fontSize: 14)), icon: Icon( // Add this Icons.arrow_drop_down, // Add this - color: widget.hintColor ?? Colors.grey , // Add this + color: widget.hintColor ?? Colors.grey , // Add thisprefixIcon ), decoration: InputDecoration( filled: true, + prefixIconColor: Colors.grey, + prefixIcon: widget.prefixIcon, suffixIconColor: widget.hintColor ?? Colors.grey , focusedBorder: InputBorder.none, fillColor: widget.filled ??Colors.white, @@ -114,7 +117,7 @@ class ShallowDropdownInputWidgetState extends State setState(() { }); }, child: Container( width: 50,height: 50, - decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: Colors.grey.shade300))), + decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: midColor))), child: Icon(widget.iconRemove ?? Icons.delete, color: widget.current == null || widget.canRemove == null || !widget.canRemove!(widget.current) ? Colors.grey : Colors.white)) ) ), ]); }); diff --git a/lib/widgets/inputs/shallow_text_input.dart b/lib/widgets/inputs/shallow_text_input.dart index 1311b89..c5f712d 100644 --- a/lib/widgets/inputs/shallow_text_input.dart +++ b/lib/widgets/inputs/shallow_text_input.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/pages/shared.dart'; class ShallowTextInputWidget extends StatefulWidget { double? width; - SharedWorkspaceType type = SharedWorkspaceType.workspace; + CollaborativeAreaType type = CollaborativeAreaType.workspace; Future Function(Map)? load; Future Function(String)? loadStr; Future Function(String)? remove; @@ -12,10 +13,12 @@ class ShallowTextInputWidget extends StatefulWidget { void Function(String?)? change; String? current; String? compare; - + bool readOnly; IconData? iconLoad; IconData? iconRemove; + MainAxisAlignment alignment = MainAxisAlignment.start; + String? hint; String? tooltipLoad; @@ -28,7 +31,7 @@ class ShallowTextInputWidget extends StatefulWidget { String? attr; - ShallowTextInputWidget ({ Key? key, this.width, this.current, this.attr, + ShallowTextInputWidget ({ Key? key, this.width, this.current, this.attr, this.readOnly = false, this.alignment = MainAxisAlignment.start, this.iconLoad, this.iconRemove, this.hint, this.forms = const [], this.loadStr, this.tooltipLoad = "", this.tooltipRemove = "", this.filled, this.hintColor, this.color, @@ -61,16 +64,17 @@ class ShallowTextInputWidgetState extends State { } @override Widget build(BuildContext context) { - var t = widget.type == SharedWorkspaceType.workspace ? "workspace" : (widget.type == SharedWorkspaceType.workflow ? "workflow" : "peer"); - return Row( children: [ + var t = widget.type == CollaborativeAreaType.workspace ? "workspace" : (widget.type == CollaborativeAreaType.workflow ? "workflow" : "peer"); + return Row( mainAxisAlignment: widget.alignment, children: [ Tooltip( message: widget.hint ?? "current $t", child: Theme( data: Theme.of(context).copyWith( - canvasColor: Colors.grey.shade300, + canvasColor: midColor, ), - child: Container( height: 50, width: (widget.width ?? MediaQuery.of(context).size.width) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50), + child: Container( height: 50, width: (widget.width ?? getMainWidth(context)) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50), decoration: const BoxDecoration( color: Colors.white ), child: TextFormField( + enabled: !widget.readOnly, onChanged: (value) { setState(() { widget.current = value; @@ -127,7 +131,7 @@ class ShallowTextInputWidgetState extends State { setState(() { }); }, child: Container( width: 50,height: 50, - decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: Colors.grey.shade300))), + decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: midColor))), child: Icon(widget.iconRemove ?? Icons.delete, color: widget.current == null || widget.canRemove == null || !widget.canRemove!(widget.current) ? Colors.grey : Colors.white)) ) ), ]); diff --git a/lib/widgets/inputs/sub_text_input.dart b/lib/widgets/inputs/sub_text_input.dart index b91e2fc..fc325aa 100644 --- a/lib/widgets/inputs/sub_text_input.dart +++ b/lib/widgets/inputs/sub_text_input.dart @@ -28,7 +28,6 @@ class SubTextInputWidgetState extends State { width: widget.width - (widget.readOnly ? 40 : 0), height: 30, child: TextFormField( textAlign: TextAlign.start, enabled: !widget.readOnly, - readOnly: widget.readOnly, initialValue: widget.initialValue, onChanged: widget.change, style: const TextStyle(fontSize: 12), @@ -40,7 +39,7 @@ class SubTextInputWidgetState extends State { alignLabelWithHint: false, errorStyle: const TextStyle(fontSize: 0), hintStyle: const TextStyle(fontSize: 10), - labelStyle: const TextStyle(fontSize: 10), + labelStyle: const TextStyle(fontSize: 12), floatingLabelBehavior: FloatingLabelBehavior.always, enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), diff --git a/lib/widgets/items/item.dart b/lib/widgets/items/item.dart index 835d23c..49f6bd8 100644 --- a/lib/widgets/items/item.dart +++ b/lib/widgets/items/item.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/widgets/items/items_details/data_item.dart'; @@ -13,23 +14,23 @@ class ItemWidgetState extends State { Widget w = Container(); /* if (isData(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } else if (isComputing(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } - else if (isDataCenter(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } + else if (isCompute(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } else if (isStorage(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } */ return Container( - height: MediaQuery.of(context).size.height - 300, + height: getHeight(context) - 300, child: SingleChildScrollView( child: Column( children: [ widget.item.description == null ? Container() : Container( - width: MediaQuery.of(context).size.width, + width: getMainWidth(context), alignment: Alignment.center, - decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey.shade300))), + decoration: BoxDecoration(border: Border(bottom: BorderSide(color: midColor))), padding: const EdgeInsets.all(30), child: Text(widget.item.description!, style: TextStyle(fontSize: 15, color: Colors.grey, fontWeight: FontWeight.w500))), Container(padding: const EdgeInsets.all(30), - color: Colors.grey.shade300, - width: MediaQuery.of(context).size.width / 2, + color: midColor, + width: getMainWidth(context) / 2, child: w ) ] diff --git a/lib/widgets/items/item_row.dart b/lib/widgets/items/item_row.dart index 33316ef..95984cd 100644 --- a/lib/widgets/items/item_row.dart +++ b/lib/widgets/items/item_row.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/core/models/workspace_local.dart'; import 'package:oc_front/core/services/router.dart'; @@ -19,7 +20,7 @@ class ItemRowWidget extends StatefulWidget { class ItemRowWidgetState extends State { @override Widget build(BuildContext context) { double imageSize = widget.contextWidth <= 400 ? 0 : 80; - var ratio = MediaQuery.of(context).size.width != widget.contextWidth ? 0.5 : 1; // 2; + var ratio = getMainWidth(context) != widget.contextWidth ? 0.5 : 1; // 2; var itemWidth = (((widget.contextWidth - imageSize) / 3) - 80) / ratio; itemWidth = itemWidth > 100 ? 100 : ( itemWidth < 40 ? 40 : itemWidth ); var endWidth = (itemWidth * ratio) + 80; @@ -31,7 +32,7 @@ class ItemRowWidgetState extends State { width: widget.contextWidth, height: 100, padding: EdgeInsets.only(left: imageSize == 0 ? 20 : 0), - decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey.shade300)) ), + decoration: BoxDecoration( border: Border(bottom: BorderSide(color: midColor)) ), child: Row( children: [ widget.low ? Container( padding: const EdgeInsets.only(left: 10),) : Container( padding: const EdgeInsets.all(10), constraints: BoxConstraints(maxWidth: imageSize, minWidth: imageSize), @@ -39,7 +40,7 @@ class ItemRowWidgetState extends State { height: imageSize, width: imageSize)), Container( width: widget.low ? widget.contextWidth - 20 : widget.contextWidth - (imageSize + 20) - endWidth, - child: Padding(padding: widget.contextWidth != MediaQuery.of(context).size.width ? + child: Padding(padding: widget.contextWidth != getMainWidth(context) ? const EdgeInsets.symmetric(horizontal: 10) : const EdgeInsets.symmetric(horizontal: 20), child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -49,11 +50,11 @@ class ItemRowWidgetState extends State { decoration: BoxDecoration( color: isData(widget.item.topic) ? Colors.blue : isComputing(widget.item.topic) ? Colors.green : - isDataCenter(widget.item.topic) ? Colors.orange : - isStorage(widget.item.topic) ? Colors.red : Colors.grey, + isCompute(widget.item.topic) ? Colors.orange : + isStorage(widget.item.topic) ? redColor : Colors.grey, borderRadius: BorderRadius.circular(4), ), - child: Text( MediaQuery.of(context).size.width < 600 ? "" : widget.item.topic.toString(), + child: Text( getMainWidth(context) < 600 ? "" : widget.item.topic.toString(), style: const TextStyle(fontSize: 10, color: Colors.white, fontWeight: FontWeight.w600)), ), Expanded( child: Text(widget.item.name?.toUpperCase() ?? "", @@ -85,8 +86,8 @@ class ItemRowWidgetState extends State { constraints: const BoxConstraints(maxWidth: 80), width: itemWidth, decoration: BoxDecoration( - boxShadow: [BoxShadow(color: Colors.grey.shade300, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))], - color: (WorkspaceLocal.hasItem(widget.item) ? Colors.red : const Color.fromRGBO(38, 166, 154, 1)), + boxShadow: [BoxShadow(color: midColor, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))], + color: (WorkspaceLocal.hasItem(widget.item) ? redColor : lightColor ), borderRadius: BorderRadius.circular(4), ), child: Icon(WorkspaceLocal.hasItem(widget.item) ? Icons.remove_shopping_cart : Icons.add_shopping_cart, @@ -101,8 +102,8 @@ class ItemRowWidgetState extends State { constraints: const BoxConstraints(maxWidth: 80, minWidth: 40), width: itemWidth, decoration: BoxDecoration( - boxShadow: [BoxShadow(color: Colors.grey.shade300, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))], - color: Colors.grey.shade300, + boxShadow: [BoxShadow(color: midColor, spreadRadius: 1, blurRadius: 1, offset: const Offset(0, 1))], + color: midColor, borderRadius: BorderRadius.circular(4), ), child: const Icon(Icons.favorite_border, color: Colors.white, size: 20 )) diff --git a/lib/widgets/items/shallow_item_row.dart b/lib/widgets/items/shallow_item_row.dart index 72d5207..97fc7c2 100644 --- a/lib/widgets/items/shallow_item_row.dart +++ b/lib/widgets/items/shallow_item_row.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/response.dart'; const List> _empty = []; @@ -51,7 +52,7 @@ class ShallowItemRowWidgetState extends State { constraints: BoxConstraints(maxWidth: widget.contextWidth, minWidth: widget.contextWidth), child: Icon( widget.icon!, size: widget.contextWidth / 1.9, color: const Color(0xFFF67C0B9),)), Container( - child: Padding(padding: widget.contextWidth != MediaQuery.of(context).size.width ? + child: Padding(padding: widget.contextWidth != getMainWidth(context) ? const EdgeInsets.symmetric(horizontal: 10) : const EdgeInsets.symmetric(horizontal: 20), child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/lib/widgets/logs.dart b/lib/widgets/logs.dart index ff0057d..cee2de2 100644 --- a/lib/widgets/logs.dart +++ b/lib/widgets/logs.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:json_string/json_string.dart'; import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/logs.dart'; import 'package:oc_front/widgets/dialog/alert.dart'; @@ -19,7 +20,7 @@ class LogsWidgetState extends State { && (widget.level?.contains(element.level ?? "") ?? true) ).map((e) => LogWidget(item: e)).toList(); return Stack( children: [ SingleChildScrollView( child: itemRows.isEmpty ? - Container( height: MediaQuery.of(context).size.height - 100 - HeaderConstants.height, + Container( height: getMainHeight(context) - 100, child: const Center( child: Text("no log registered", style: TextStyle(color: Colors.grey, fontSize: 25 ),))) : Column( children: [...itemRows, Container(height: 50,) ] ) ), ]); @@ -47,7 +48,7 @@ class LogWidgetState extends State { 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() == "error" ? redColor : ( widget.item.level?.toLowerCase() == "warning" ? Colors.orange : Colors.blue))), InkWell( mouseCursor: map.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, onTap: () { if (map.isNotEmpty ) { diff --git a/lib/widgets/menus/arrow_clipper.dart b/lib/widgets/menus/arrow_clipper.dart deleted file mode 100644 index 785a9b3..0000000 --- a/lib/widgets/menus/arrow_clipper.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/material.dart'; - -class ArrowClipper extends CustomClipper { - @override - Path getClip(Size size) { - Path path = Path(); - path.moveTo(0, size.height); - path.lineTo(size.width / 2, size.height / 2); - path.lineTo(size.width, size.height); - return path; - } - - @override - bool shouldReclip(CustomClipper oldClipper) { - return true; - } -} \ No newline at end of file diff --git a/lib/widgets/menus/clipper_menu.dart b/lib/widgets/menus/clipper_menu.dart deleted file mode 100644 index eef2782..0000000 --- a/lib/widgets/menus/clipper_menu.dart +++ /dev/null @@ -1,218 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:oc_front/core/services/router.dart'; -import 'package:oc_front/widgets/menus/arrow_clipper.dart'; - -class TooltipWidget extends StatefulWidget { - int index = -1; - Size? buttonSize; - List labels; - Offset? buttonPosition; - TooltipWidget ({ Key? key, - required this.labels, - required this.index, - required this.buttonSize, - required this.buttonPosition }): super(key: key); - @override TooltipWidgetState createState() => TooltipWidgetState(); -} -class TooltipWidgetState extends State { - @override Widget build(BuildContext context) { - double minimal = (widget.index < 0 ? 0 : 7 * widget.labels[widget.index].length).toDouble() + 30; - return Positioned( - top : ((widget.buttonPosition?.dy ?? 1 ) + 11) + (((widget.buttonSize?.height) ?? 1)* 1.5) * (widget.index + 1), - left: (widget.buttonPosition?.dx ?? 1) - minimal, - child: Container( - width: widget.index < 0 ? 0 : (widget.index < 0 ? 0 : minimal), - height: (widget.buttonSize?.height ?? 1) - 2, - color: Colors.black, - child: Text( widget.index < 0 ? "" : widget.labels[widget.index], - style: const TextStyle( - color: Colors.white, - decoration: TextDecoration.none, - fontSize: 14, - fontWeight: FontWeight.w300), - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis - ), - )); - } -} - -GlobalKey headerMenuKey = GlobalKey(); -class ClipperMenuWidget extends StatefulWidget { - final BorderRadius borderRadius; - final Color backgroundColor; - final Color iconColor; - int index = -1; - - ClipperMenuWidget({ - required this.borderRadius, - this.backgroundColor = const Color.fromRGBO(38, 166, 154, 1), - this.iconColor = Colors.black, - }) : super(key: headerMenuKey); - @override - // ignore: library_private_types_in_public_api - ClipperMenuWidgetState createState() => ClipperMenuWidgetState(); -} - -class ClipperMenuWidgetState extends State with SingleTickerProviderStateMixin { - late GlobalKey _key; - bool isMenuOpen = false; - Offset? buttonPosition; - Size? buttonSize; - final GlobalKey _tooltipKey = GlobalKey(); - OverlayEntry? _overlayEntry; - BorderRadius? _borderRadius; - AnimationController? _animationController; - - @override - void initState() { - _animationController = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 250), - ); - _borderRadius = widget.borderRadius; // BorderRadius.circular(4) - super.initState(); - } - - @override - void dispose() { - _animationController?.dispose(); - super.dispose(); - } - - findButton() { - if (_key.currentContext != null) { - RenderBox renderBox = _key.currentContext?.findRenderObject()! as RenderBox; - buttonSize = renderBox.size; - buttonPosition = renderBox.localToGlobal(Offset.zero); - } - } - - void closeMenu() { - try { - _overlayEntry?.remove(); - _animationController?.reverse(); - isMenuOpen = false; - } catch (e) { } - - } - - void openMenu() { - findButton(); - _animationController?.forward(); - _overlayEntry = _overlayEntryBuilder(); - if (_overlayEntry != null) { Overlay.of(context).insert(_overlayEntry!); } - isMenuOpen = true; - } - - @override - Widget build(BuildContext context) { - _key = GlobalKey(); - headerMenuKey = GlobalKey(); - return Container( - key: _key, - padding: const EdgeInsets.all(0), - child: IconButton( - splashRadius: 4, - icon: _animationController == null ? - const Icon( - Icons.close, - ) : AnimatedIcon( - icon: AnimatedIcons.menu_close, - progress: _animationController!, - ), - onPressed: () { - if (isMenuOpen) { closeMenu(); - } else { openMenu(); } - }, - ), - ); - } - - OverlayEntry _overlayEntryBuilder() { - var routes = AppRouter.zones.where( - (e) => e.path != AppRouter.currentRoute.path && e.label != null && e.icon != null).toList(); - return OverlayEntry( - builder: (context) { - return Stack( children: [ - TooltipWidget( - key: _tooltipKey, - labels: routes.map((e) => e.label!).toList(), - buttonPosition: buttonPosition, - buttonSize: buttonSize, - index: widget.index - ), - Positioned( - top: (buttonPosition?.dy ?? 1 ) + (buttonSize?.height ?? 1), - left: buttonPosition?.dx, - width: buttonSize?.width, - child: Material( - color: Colors.transparent, - child: Stack( - children: [ - Align( - alignment: Alignment.topCenter, - child: ClipPath( - clipper: ArrowClipper(), - child: Container( - width: 17, - height: 17, - color: widget.backgroundColor ?? Color(0xFFF), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 15.0), - child: Container( - height: routes.length * ((buttonSize?.height ?? 1) * 1.5), - decoration: BoxDecoration( - boxShadow: const [BoxShadow(color: Colors.black54, spreadRadius: 1, blurRadius: 1, offset: Offset(0, 1))], - color: widget.backgroundColor, - borderRadius: _borderRadius, - ), - child: Theme( - data: ThemeData( - iconTheme: IconThemeData( color: widget.iconColor ), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: List.generate(routes.length, (index) { - return GestureDetector( - onTap: () { - if (index >= 0) { routes[index].go(context, {}); } - closeMenu(); - }, - child: Container( - decoration: index == (routes.length - 1) ? null : const BoxDecoration( - border: Border( bottom: BorderSide(color: Colors.white ), ), - ), - width: (buttonSize?.width ?? 1) * 1.5, - height: (buttonSize?.height ?? 1) * 1.5, - child: MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (state) { - _tooltipKey.currentState?.setState(() { - _tooltipKey.currentState?.widget.index = index; - }); - }, - onExit: (state) { - _tooltipKey.currentState?.setState(() { _tooltipKey.currentState?.widget.index = -1; }); - }, - child: Icon( routes[index].icon, size: 19) - ), - ), - ); - }), - ), - ), - ), - ), - ], - ), - ), - ) - ]); - }, - ); - } -} \ No newline at end of file diff --git a/lib/widgets/sheduler_items/schedule.dart b/lib/widgets/sheduler_items/schedule.dart index 241c01b..09fe5e1 100644 --- a/lib/widgets/sheduler_items/schedule.dart +++ b/lib/widgets/sheduler_items/schedule.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_box_transform/flutter_box_transform.dart'; import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/logs.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/widgets/logs.dart'; @@ -26,7 +27,7 @@ String? selectedReal; class ScheduleWidgetState extends State { String search = ""; String? level; - List colors = [Colors.blue, Colors.orange, Colors.red, Colors.green]; + List colors = [Colors.blue, Colors.orange, redColor, Colors.green]; List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"]; DateTime getFocusedDay() { @@ -35,8 +36,8 @@ class ScheduleWidgetState extends State { } @override Widget build(BuildContext context) { - bool isInfo = MediaQuery.of(context).size.width <= 600 && selected != null; - double w = selected != null ? MediaQuery.of(context).size.width - menuSize : MediaQuery.of(context).size.width; + bool isInfo = getMainWidth(context) <= 600 && selected != null; + double w = selected != null ? getMainWidth(context) - menuSize : getMainWidth(context); List children = []; if (selected != null) { for (var wf in widget.data[selected!] ?? ([])) { @@ -45,8 +46,7 @@ class ScheduleWidgetState extends State { 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), + border: Border.all(color: selectedReal != null && selectedReal == wf.executionData ? lightColor : Colors.transparent, width: 2), borderRadius: BorderRadius.circular(4), color: Colors.white ), child: Container( @@ -85,9 +85,9 @@ class ScheduleWidgetState extends State { logs = sel.logs ?? []; } catch(e) { /* */ } } - menuSize = isInfo ? MediaQuery.of(context).size.width : (menuSize > MediaQuery.of(context).size.width / 2 ? MediaQuery.of(context).size.width / 2 : menuSize); + menuSize = isInfo ? getMainWidth(context) : (menuSize > getMainWidth(context) / 2 ? getMainWidth(context) / 2 : menuSize); Rect rect = Rect.fromCenter( center: MediaQuery.of(context).size.center(Offset.zero), - width: selected != null ? menuSize : 0, height: (MediaQuery.of(context).size.height - HeaderConstants.height - 50) > 0 ? (MediaQuery.of(context).size.height - HeaderConstants.height - 50) : 0); + width: selected != null ? menuSize : 0, height: (getMainHeight(context) - 50) > 0 ? (getMainHeight(context) - 50) : 0); return Row( children: [ isInfo ? Container() : SizedBox( width: w, child: widget.isList ? SchedulerItemWidget(data: widget.data, parent: this, focusedDay: getFocusedDay(), width: w) @@ -96,7 +96,7 @@ class ScheduleWidgetState extends State { ), fork.TransformableBox( rect: rect, constraints: BoxConstraints( - maxWidth: isInfo ? MediaQuery.of(context).size.width : (selected != null ? MediaQuery.of(context).size.width / 2 : 0), + maxWidth: isInfo ? getMainWidth(context) : (selected != null ? getMainWidth(context) / 2 : 0), minWidth: selected != null ? 300 : 0), handleTapSize: 1, handleTapLeftSize: 0, allowFlippingWhileResizing: false, draggable: false, flip: null, resizeModeResolver: () => ResizeMode.freeform, @@ -106,15 +106,15 @@ class ScheduleWidgetState extends State { handleAlignment: HandleAlignment.inside, onChanged: (result, event) { setState(() { menuSize = result.rect.width; }); }, contentBuilder: (context, rect, flip) { return Container( - height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, - width: isInfo ? MediaQuery.of(context).size.width : (selected != null ? menuSize : 0), - color: Colors.grey.shade300, + height: getMainHeight(context) - 50, + width: isInfo ? getMainWidth(context) : (selected != null ? menuSize : 0), + color: midColor, 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 ? menuSize : 0)) / (selectedReal != null ? 2 : 1 ), + Container( height: 50, width: (isInfo ? getMainWidth(context) : (selected != null ? menuSize : 0)) / (selectedReal != null ? 2 : 1 ), alignment: Alignment.center, decoration: BoxDecoration( color: widget.isDayPlanner ? Colors.grey : Colors.transparent, @@ -125,7 +125,7 @@ class ScheduleWidgetState extends State { 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 ? menuSize : 0)) / 2), + (isInfo ? getMainWidth(context) : (selected != null ? menuSize : 0)) / 2), alignment: Alignment.center, decoration: BoxDecoration( color: !widget.isDayPlanner ? Colors.grey : Colors.transparent, @@ -136,7 +136,7 @@ class ScheduleWidgetState extends State { ) )) ]), - SizedBox( width: isInfo ? MediaQuery.of(context).size.width : (selected != null ? menuSize : 0), height: MediaQuery.of(context).size.height - HeaderConstants.height - (!widget.isDayPlanner && !widget.loading ? 150 : 100 ), + SizedBox( width: isInfo ? getMainWidth(context) : (selected != null ? menuSize : 0), height: getMainHeight(context) - (!widget.isDayPlanner && !widget.loading ? 150 : 100 ), child: Stack( children: [ SingleChildScrollView( child: Column( mainAxisAlignment: children.isEmpty || widget.loading ? MainAxisAlignment.center : MainAxisAlignment.start, @@ -154,7 +154,7 @@ class ScheduleWidgetState extends State { width: 150, height: 50, decoration: BoxDecoration( - border: Border(left: BorderSide(color: Colors.grey.shade300)), + border: Border(left: BorderSide(color: midColor)), ), child: DropdownButtonFormField( isExpanded: true, @@ -163,22 +163,22 @@ class ScheduleWidgetState extends State { hint: const Text("by level...", style: TextStyle(fontSize: 12)), decoration: InputDecoration( filled: true, - focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, - borderSide: BorderSide(color: Color.fromARGB(38, 166, 154, 1), width: 0), + focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.zero, + borderSide: BorderSide(color: lightColor, width: 0), ), fillColor: Colors.white, contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 10, bottom: 30), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.zero, - borderSide: BorderSide(color: Colors.grey.shade300, width: 0), + borderSide: BorderSide(color: midColor, width: 0), ), border: OutlineInputBorder( borderRadius: BorderRadius.zero, - borderSide: BorderSide(color: Colors.grey.shade300, width: 0)), + borderSide: BorderSide(color: midColor, width: 0)), ), items: [ DropdownMenuItem(value: "debug,warning,error,info", child: Row( children: [ Container( width: 10, height: 15, color: Colors.grey), Text(" all", style: TextStyle(fontSize: 12, color: Colors.black)) ])), DropdownMenuItem(value: "debug", child: Row( children: [ Container( width: 10, height: 15, color: Colors.blue), Text(" debug", style: TextStyle(fontSize: 12, color: Colors.black)) ])), DropdownMenuItem(value: "warning", child: Row( children: [ Container( width: 10, height: 15, color: Colors.orange), Text(" warning", style: TextStyle(fontSize: 12, color: Colors.black)) ])), - DropdownMenuItem(value: "error", child: Row( children: [ Container( width: 10, height: 15, color: Colors.red), Text(" error", style: TextStyle(fontSize: 12, color: Colors.black)) ])), + DropdownMenuItem(value: "error", child: Row( children: [ Container( width: 10, height: 15, color: redColor), Text(" error", style: TextStyle(fontSize: 12, color: Colors.black)) ])), DropdownMenuItem(value: "info", child: Row( children: [ Container( width: 10, height: 15, color: Colors.green), Text(" info", style: TextStyle(fontSize: 12, color: Colors.black)) ])), ], onChanged: (value) { @@ -190,7 +190,7 @@ class ScheduleWidgetState extends State { width: menuSize - 150, height: 50, decoration: BoxDecoration( - border: Border(left: BorderSide(color: Colors.grey.shade300)), + border: Border(left: BorderSide(color: midColor)), ), child: TextField( onChanged: (value) { setState(() { diff --git a/lib/widgets/sheduler_items/scheduler_calendar.dart b/lib/widgets/sheduler_items/scheduler_calendar.dart index ad6f0dc..a0dc983 100644 --- a/lib/widgets/sheduler_items/scheduler_calendar.dart +++ b/lib/widgets/sheduler_items/scheduler_calendar.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:oc_front/core/sections/header/header.dart'; +import 'package:oc_front/main.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/widgets/sheduler_items/schedule.dart'; import 'package:table_calendar/table_calendar.dart'; @@ -23,7 +24,7 @@ class SchedulerCalendarWidget extends StatefulWidget { @override SchedulerCalendarWidgetState createState() => SchedulerCalendarWidgetState(); } class SchedulerCalendarWidgetState extends State { - List colors = [Colors.blue, Colors.orange, Colors.red, Colors.green]; + List colors = [Colors.blue, Colors.orange, redColor, Colors.green]; List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"]; bool isEvent(Map> data, DateTime day) { if (data[day.toIso8601String()] == null || data[day.toIso8601String()]!.isEmpty) { return false; } @@ -34,7 +35,7 @@ class SchedulerCalendarWidgetState extends State { 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, + height: getMainHeight(context) - 50, child: TableCalendar( firstDay: widget.start, lastDay: widget.end, @@ -61,7 +62,7 @@ class SchedulerCalendarWidgetState extends State { padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 2), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), - color: Colors.grey.shade300, + color: midColor, ), child: const Text("...", style: TextStyle(color: Colors.white, fontSize: 10)), ))); @@ -90,7 +91,7 @@ class SchedulerCalendarWidgetState extends State { alignment: !isEvent(widget.data, date) ? Alignment.center : Alignment.topCenter, margin:const EdgeInsets.all(2.0), decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), + border: Border.all(color: midColor), shape: BoxShape.rectangle, ), child: !isEvent(widget.data, date) ? Text( @@ -106,8 +107,8 @@ class SchedulerCalendarWidgetState extends State { alignment: Alignment.center, margin: const EdgeInsets.all(2.0), decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), - color: Colors.grey.shade300, + border: Border.all(color: midColor), + color: midColor, shape: BoxShape.rectangle, ), child: Text( @@ -119,7 +120,7 @@ class SchedulerCalendarWidgetState extends State { alignment: !isEvent(widget.data, date) ? Alignment.center : Alignment.topCenter, margin: const EdgeInsets.all(2.0), decoration: BoxDecoration( - border: Border.all(color: const Color.fromRGBO(38, 166, 154, 1), width: 2), + border: Border.all(color: lightColor, width: 2), shape: BoxShape.rectangle, ), child: !isEvent(widget.data, date) ? Text( diff --git a/library/flutter_flow_chart/lib/src/dashboard.dart b/library/flutter_flow_chart/lib/src/dashboard.dart index d75c958..1bb4a8f 100755 --- a/library/flutter_flow_chart/lib/src/dashboard.dart +++ b/library/flutter_flow_chart/lib/src/dashboard.dart @@ -27,6 +27,7 @@ class Dashboard extends ChangeNotifier { GlobalKey selectedLeftMenuKey = GlobalKey(); GlobalKey chartMenuKey = GlobalKey(); GlobalKey chartKey = GlobalKey(); + GlobalKey flutterChartKey = GlobalKey(); List> tempHistory = []; List> history = []; Map scheduler = {}; @@ -50,12 +51,23 @@ class Dashboard extends ChangeNotifier { FlowData? Function(Map json)? transformToData; bool addChange = false; bool shouldSave = true; + Color dashColor = Colors.grey; + Color midDashColor = Colors.grey.shade300; + + /// The dashboard position + /// This is used to move the dashboard on the screen + double widthOffset = 0; + double heightOffset = 0; /// Dashboard({ this.id, + this.widthOffset = 0, + this.heightOffset = 0, this.transformToData, required this.name, this.save, + this.dashColor = Colors.grey, + this.midDashColor = Colors.blueGrey, this.scheduler = const {}, Offset? handlerFeedbackOffset, this.isMenu = true, @@ -384,7 +396,6 @@ class Dashboard extends ChangeNotifier { FlowElement? getElement(String id, {bool notify = true}) { try { return elements.firstWhere((element) { - print(element.id + " - " + id); return element.id == id; }); } catch (e) { return null; } @@ -523,6 +534,9 @@ class Dashboard extends ChangeNotifier { void removeAllElements({bool notify = true}) { elements.clear(); if (notify) notifyListeners(); + if (save != null) { + save!(id); + } } /// remove the [handler] connection of [element] @@ -564,8 +578,10 @@ class Dashboard extends ChangeNotifier { ); } } - if (notify) notifyListeners(); + if (save != null) { + save!(id); + } } /// dissect an element connection @@ -658,6 +674,9 @@ class Dashboard extends ChangeNotifier { void removeElementConnections(FlowElement element, {bool notify = true}) { element.next.clear(); if (notify) notifyListeners(); + if (save != null) { + save!(id); + } } /// remove all the elements with [id] from the dashboard @@ -678,6 +697,9 @@ class Dashboard extends ChangeNotifier { }); } if (notify) notifyListeners(); + if (save != null) { + save!(id); + } } /// remove element @@ -698,6 +720,9 @@ class Dashboard extends ChangeNotifier { ); } if (notify) notifyListeners(); + if (save != null) { + save!(id); + } return found; } diff --git a/library/flutter_flow_chart/lib/src/elements/flow_element.dart b/library/flutter_flow_chart/lib/src/elements/flow_element.dart index 467740e..d8e5d28 100755 --- a/library/flutter_flow_chart/lib/src/elements/flow_element.dart +++ b/library/flutter_flow_chart/lib/src/elements/flow_element.dart @@ -68,7 +68,7 @@ class FlowElement extends ChangeNotifier { FlowElement({ required this.dashboard, Offset position = Offset.zero, - String? id, + String? id, this.element, this.size = Size.zero, this.text = '', diff --git a/library/flutter_flow_chart/lib/src/flow_chart.dart b/library/flutter_flow_chart/lib/src/flow_chart.dart index 18f827d..0028e3c 100755 --- a/library/flutter_flow_chart/lib/src/flow_chart.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart.dart @@ -60,6 +60,8 @@ class FlowChart extends StatefulWidget { this.menuWidget, this.current, this.menuExtension, + this.itemLeftBottomBadges, + this.itemrightTopBadges, }) {} final String? current; final List categories; @@ -74,6 +76,8 @@ class FlowChart extends StatefulWidget { double zoom = 1; final Widget Function(T data) itemWidget; + final Widget? Function(T data)? itemLeftBottomBadges; + final Widget? Function(T data)? itemrightTopBadges; final Widget Function(T data)? itemWidgetTooltip; final List Function(String cat) draggableItemBuilder; @@ -274,7 +278,7 @@ class HoverMenuState extends State { return OverlayEntry( maintainState: true, builder: (context) => Positioned( - left: offset.dx, + left: offset.dx - 300, top: offset.dy + size.height, width: 300, child: TextButton( @@ -451,7 +455,10 @@ class FlowChartState extends State { String newID = const Uuid().v4(); double ratio = 1; if (e.getWidth() != null && e.getHeight() != null) { - ratio = (e.getHeight()! / (e.getWidth()!)); + print("${e.getWidth()} ${e.getHeight()}"); + var h = e.getHeight()! < e.getWidth()! ? e.getHeight()! + 20 : e.getHeight()!; + var w = e.getWidth()! < e.getHeight()! ? e.getWidth()! + 20 : e.getWidth()!; + ratio = (h / w); } FlowElement el = FlowElement( dashboard: widget.dashboard, @@ -474,25 +481,22 @@ class FlowChartState extends State { }, ))] ), - widget.dashboard.isMenu ? Positioned(top: 50, child: FlowChartLeftMenu( - key: widget.dashboard.selectedLeftMenuKey, + widget.dashboard.isMenu ? Positioned(top: 50, child: FlowChartSelectedMenu( + key: widget.dashboard.selectedMenuKey, dashboard: widget.dashboard, - menuExtension: widget.menuExtension, - categories: widget.categories, - height: widget.height, - innerMenuWidth: widget.innerMenuWidth, - itemWidth: widget.itemWidth, - draggableItemBuilder: widget.draggableItemBuilder as List Function(String cat), - getDraggable: getDraggable, - ) ) - : Container(), + height: widget.height - 50) ) : 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() + FlowChartLeftMenu( + key: widget.dashboard.selectedLeftMenuKey, + dashboard: widget.dashboard, + menuExtension: widget.menuExtension, + categories: widget.categories, + height: widget.height, + innerMenuWidth: widget.innerMenuWidth, + itemWidth: widget.itemWidth, + draggableItemBuilder: widget.draggableItemBuilder as List Function(String cat), + getDraggable: getDraggable, + )) : Container() ]) )); } @@ -509,19 +513,16 @@ class FlowChartState extends State { onDragEnd: (d) => node.requestFocus(), childWhenDragging: Opacity(opacity: .5, child: Padding( padding: const EdgeInsets.all(10), - child: Container( child: widget.itemWidget(e), - constraints: BoxConstraints(maxHeight: realSize - 20, maxWidth: realSize - 20), ))), - feedback: Container( constraints: BoxConstraints(maxHeight: realSize, maxWidth: realSize), + child: Container( child: widget.itemWidget(e), alignment: Alignment.center, + constraints: BoxConstraints(maxHeight: realSize - 10, maxWidth: realSize - 10), ))), + feedback: Container( alignment: Alignment.center, constraints: BoxConstraints(maxHeight: realSize, maxWidth: 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( - constraints: BoxConstraints( maxHeight: realSize - 20, maxWidth: realSize - 20), - child: widget.itemWidget(e) ), - items: [ - Container(child: widget.itemWidgetTooltip!(e)), - ] - ) : Container( - constraints: BoxConstraints(maxHeight: realSize - 20, maxWidth: realSize - 20), child: widget.itemWidget(e) + child: widget.itemWidgetTooltip != null ? HoverMenu( key: hoverKey, width: 400, title: Container( alignment: Alignment.center, + constraints: BoxConstraints( maxHeight: realSize - 10, maxWidth: realSize - 10), child: widget.itemWidget(e) ), + items: [ Container(child: widget.itemWidgetTooltip!(e)) ] + ) : Container( alignment: Alignment.center, + constraints: BoxConstraints(maxHeight: realSize - 10, maxWidth: realSize - 10), child: widget.itemWidget(e) ) ) ))); } @@ -824,6 +825,10 @@ class ChartWidgetState extends State { for (int i = 0; i < widget.dashboard.elements.length; i++) ElementWidget( key: UniqueKey(), + bottomLeftBadge: widget.flowChart.widget.itemLeftBottomBadges != null ? + widget.flowChart.widget.itemLeftBottomBadges!(widget.dashboard.elements[i].element as T) : null, + topRightBadge: widget.flowChart.widget.itemrightTopBadges != null ? + widget.flowChart.widget.itemrightTopBadges!(widget.dashboard.elements[i].element as T) : null, dashboard: widget.dashboard, element: widget.dashboard.elements.elementAt(i), onElementPressed: widget.onElementPressed == null @@ -924,7 +929,7 @@ class ChartWidgetState extends State { chart: this, menuExtension: widget.menuWidget != null ? widget.menuWidget!(widget.dashboard) : null, dashboard: widget.dashboard, - width: MediaQuery.of(context).size.width) + width: widget.flowChart.widget.width) ), ], ); diff --git a/library/flutter_flow_chart/lib/src/flow_chart_left_menu.dart b/library/flutter_flow_chart/lib/src/flow_chart_left_menu.dart index 98b303f..047ced3 100644 --- a/library/flutter_flow_chart/lib/src/flow_chart_left_menu.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart_left_menu.dart @@ -37,7 +37,7 @@ class FlowChartLeftMenuState extends State extends State extends State { @override Widget build(BuildContext context) { - bool isLow = MediaQuery.of(context).size.width < 600; + bool isLow = widget.chart.widget.flowChart.widget.width < 600; GlobalKey zoomKey = GlobalKey(); - return Container( // SHORTCUT + return Row( mainAxisAlignment: MainAxisAlignment.end, children : [ Container( // SHORTCUT width: widget.width, height: 50, padding: EdgeInsets.only(left: 20), - color: const Color.fromRGBO(38, 166, 154, 1), + color: widget.dashboard.dashColor, child: Row( children : [ Expanded(flex: 2, child: Row( children: [ widget.chart.widget.flowChart.widget.onDashboardAlertOpened == null ? Container() : Container( decoration: BoxDecoration( @@ -49,7 +49,7 @@ class FlowChartMenuState extends State { context, widget.dashboard)); }); }, - child: Icon(Icons.folder_open, color: Colors.white))))), + child: Icon(Icons.folder, color: Colors.white))))), ])), InkWell( mouseCursor: SystemMouseCursors.click, child: Container( decoration: BoxDecoration( @@ -109,7 +109,7 @@ class FlowChartMenuState extends State { child: Wrap( alignment: WrapAlignment.center, children: [ Padding( padding: EdgeInsets.only(left: 10, top: 10, bottom: 10) , child: TextFormField( key: zoomKey, - cursorColor: const Color.fromARGB(38, 166, 154, 1), + cursorColor: widget.dashboard.dashColor, onChanged: (value) { }, validator: (value) { try { @@ -224,7 +224,7 @@ class FlowChartMenuState extends State { } }, mouseCursor: !widget.dashboard.canBack() ? MouseCursor.defer : SystemMouseCursors.click, - child: Icon(Icons.undo, color: !widget.dashboard.canBack() ? Colors.grey.shade300 : Colors.white)),), + child: Icon(Icons.undo, color: !widget.dashboard.canBack() ? widget.dashboard.midDashColor : Colors.white)),), Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: InkWell( onTap: () { @@ -233,22 +233,22 @@ class FlowChartMenuState extends State { } }, mouseCursor: !widget.dashboard.canForward() ? MouseCursor.defer : SystemMouseCursors.click, child: Icon(Icons.redo, - color: !widget.dashboard.canForward() ? Colors.grey.shade300 : Colors.white))), + color: !widget.dashboard.canForward() ? widget.dashboard.midDashColor : Colors.white))), ])), Expanded( - child: Padding( child: Text("file opened : ${widget.dashboard.name}", overflow: TextOverflow.ellipsis, + child: Padding( child: Text("current workflow : ${widget.dashboard.name}", overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.white, fontSize: 14), textAlign: TextAlign.start), padding: EdgeInsets.symmetric(horizontal: 20))), ])), - widget.menuExtension != null && MediaQuery.of(context).size.width > 600 ? Container( + widget.menuExtension != null && widget.chart.widget.flowChart.widget.width > 600 ? Container( decoration: BoxDecoration( border: Border(left: BorderSide(color: Colors.white, width: 1)) ), child: widget.menuExtension ) : Container() ]) - ); + ) ]); } } diff --git a/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart b/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart index d21b1c1..77b8fbf 100644 --- a/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart @@ -17,13 +17,13 @@ class FlowChartSelectedMenuState extends State { Widget? w; if (widget.isDashboardInfo && widget.dashboard.elementSelected.length == 1) { w = Container( - width: 250, + width: 200, height: widget.height, - color: Colors.grey.shade300, - child: Column( children: [ ...widget.dashboard.infoItemWidget != null ? + color: widget.dashboard.midDashColor, + child: SingleChildScrollView( child: Column( children: [ ...widget.dashboard.infoItemWidget != null ? widget.dashboard.infoItemWidget!(widget.dashboard.elementSelected.first.element, widget.dashboard.elementSelected.first.id) : [], widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container( - width: 250, + width: 200, margin: EdgeInsets.only(top: 15), decoration: BoxDecoration(border: Border( top: BorderSide(color: Colors.grey, width: 1))), @@ -66,44 +66,44 @@ class FlowChartSelectedMenuState extends State { ]) ) : Container() ]) - ); + )); } else if (widget.isDashboardInfo && widget.dashboard.infoWidget != null) { w = Container( - width: 250, + width: 200, height: widget.height, - color: Colors.grey.shade300, + color: widget.dashboard.midDashColor, child: Column( children: widget.dashboard.infoWidget != null ? widget.dashboard.infoWidget!() : []) ); } else { w = Container( // SHORTCUT - width: 250, + width: 200, height: widget.height, - color: Colors.grey.shade300, + color: widget.dashboard.midDashColor, child: Column( children: [ - Container( padding: EdgeInsets.all(10), width: 250, height: 60, + Container( padding: EdgeInsets.all(10), width: 200, height: 60, decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("STYLE ${widget.dashboard.elementSelected.isNotEmpty ? "ELEMENT" : "ARROW"}", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Text("<${widget.dashboard.arrowsSelected.isEmpty && widget.dashboard.elementSelected.isEmpty ? "general" : "selected"}>", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), ])), - Container( width: 250, height: widget.height - 60, child: SingleChildScrollView( child: Column( children: [ + Container( width: 200, height: widget.height - 60, child: SingleChildScrollView( child: Column( children: [ widget.dashboard.elementSelected.isNotEmpty ? Container() : Container( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Column( children: [ Row( children: [ InkWell( mouseCursor: SystemMouseCursors.click, child: Container( - child: Padding( padding: EdgeInsets.symmetric(horizontal: 10), + child: Padding( padding: EdgeInsets.only(left: 10, right: 10), child: PopupMenuButton( tooltip: "line defaults", constraints: BoxConstraints(maxWidth: 100), child: Row( children: [ MySeparator( - width: 65, + width: 35, dashWidth: widget.dashboard.defaultDashWidth, dashSpace: widget.dashboard.defaultDashSpace, color: Colors.black ), - Container(height: 25, width: 10), + SizedBox(height: 25, width: 10), Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ]), initialValue: null, onSelected: (ArrowDash value) { @@ -122,44 +122,44 @@ class FlowChartSelectedMenuState extends State { PopupMenuItem( value: ArrowDash.line, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - MySeparator(width: 50, dashWidth: widthArrowDash(ArrowDash.line), + MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.line), dashSpace: spaceArrowDash(ArrowDash.line),) ]), ), PopupMenuItem( value: ArrowDash.largeDash, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - MySeparator(width: 50, dashWidth: widthArrowDash(ArrowDash.largeDash), dashSpace: spaceArrowDash(ArrowDash.largeDash),) + MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.largeDash), dashSpace: spaceArrowDash(ArrowDash.largeDash),) ]), ), PopupMenuItem( value: ArrowDash.mediumDash, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - MySeparator(width: 50, dashWidth: widthArrowDash(ArrowDash.mediumDash), dashSpace: spaceArrowDash(ArrowDash.mediumDash),) + MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.mediumDash), dashSpace: spaceArrowDash(ArrowDash.mediumDash),) ]), ), PopupMenuItem( value: ArrowDash.smallDash, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - MySeparator(width: 50, dashWidth: widthArrowDash(ArrowDash.smallDash), dashSpace: spaceArrowDash(ArrowDash.smallDash),) + MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.smallDash), dashSpace: spaceArrowDash(ArrowDash.smallDash),) ]), ), PopupMenuItem( value: ArrowDash.heavyDotted, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - MySeparator(width: 50, dashWidth: widthArrowDash(ArrowDash.heavyDotted), dashSpace: spaceArrowDash(ArrowDash.heavyDotted),) + MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.heavyDotted), dashSpace: spaceArrowDash(ArrowDash.heavyDotted),) ]), ), PopupMenuItem( value: ArrowDash.mediumDotted, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - MySeparator(width: 50, dashWidth: widthArrowDash(ArrowDash.mediumDotted), dashSpace: spaceArrowDash(ArrowDash.mediumDotted),) + MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.mediumDotted), dashSpace: spaceArrowDash(ArrowDash.mediumDotted),) ]), ), PopupMenuItem( value: ArrowDash.lightDotted, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - MySeparator(width: 50, dashWidth: widthArrowDash(ArrowDash.lightDotted), dashSpace: spaceArrowDash(ArrowDash.lightDotted),) + MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.lightDotted), dashSpace: spaceArrowDash(ArrowDash.lightDotted),) ]), ), ] @@ -191,7 +191,7 @@ class FlowChartSelectedMenuState extends State { Tooltip( message: "stroke width", child: Container( margin: EdgeInsets.only(left: 10), - width: 75, height: 25, + width: 55, height: 25, child: TextFormField( textAlign: TextAlign.center, readOnly: widget.dashboard.defaultDashWidth <= 0, initialValue: "${widget.dashboard.defaultStroke}", @@ -278,7 +278,7 @@ class FlowChartSelectedMenuState extends State { Tooltip( message: "space dash", child: Container( margin: EdgeInsets.only(top: 10), - width: 155 / 2, height: 25, + width: 105 / 2, height: 25, child: TextFormField( textAlign: TextAlign.center, readOnly: widget.dashboard.defaultDashWidth <= 0, initialValue: "${widget.dashboard.defaultDashWidth}", @@ -291,7 +291,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? widget.dashboard.midDashColor : Colors.white, filled: true, labelText: "dash", labelStyle: TextStyle(fontSize: 10), @@ -316,7 +316,7 @@ class FlowChartSelectedMenuState extends State { Tooltip( message: "space width", child: Container( margin: EdgeInsets.only(left: 10, top: 10), - width: 155 / 2, height: 25, + width: 105 / 2, height: 25, child: TextFormField( textAlign: TextAlign.center, initialValue: "${widget.dashboard.defaultDashSpace}", onChanged: (value) { @@ -328,7 +328,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? widget.dashboard.midDashColor : Colors.white, filled: true, labelText: "space", labelStyle: TextStyle(fontSize: 10), @@ -411,8 +411,8 @@ class FlowChartSelectedMenuState extends State { Row(children: [ Tooltip( message: "forward size", child: Container( - margin: EdgeInsets.only(left: 10, top: 10), - width: 185, height: 25, + margin: EdgeInsets.only(top: 10), + width: 150, height: 25, child: TextFormField( textAlign: TextAlign.center, initialValue: "${widget.dashboard.defaultForwardWidth}", onChanged: (value) { @@ -436,7 +436,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? widget.dashboard.midDashColor : Colors.white, filled: true, labelText: "forward size", labelStyle: TextStyle(fontSize: 10), @@ -463,8 +463,8 @@ class FlowChartSelectedMenuState extends State { Row(children: [ Tooltip( message: "back size", child: Container( - margin: EdgeInsets.only(left: 10, top: 10), - width: 185, height: 25, + margin: EdgeInsets.only(top: 10), + width: 150, height: 25, child: TextFormField( textAlign: TextAlign.center, initialValue: "${widget.dashboard.defaultBackWidth}", onChanged: (value) { @@ -488,7 +488,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? widget.dashboard.midDashColor : Colors.white, filled: true, labelText: "back size", labelStyle: TextStyle(fontSize: 10), @@ -514,7 +514,7 @@ class FlowChartSelectedMenuState extends State { ]) ])), widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container( - width: 250, + width: 200, decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [ Tooltip( message: "remove", @@ -560,9 +560,9 @@ class FlowChartSelectedMenuState extends State { } return Column( children: [ Container( // SHORTCUT - width: 250, + width: 200, height: 50, - decoration: BoxDecoration(color: Colors.grey.shade300, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), + decoration: BoxDecoration(color: widget.dashboard.midDashColor, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Row( children: [ Tooltip( message: "dashboard information", @@ -570,8 +570,8 @@ class FlowChartSelectedMenuState extends State { mouseCursor: SystemMouseCursors.click, child: Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 10), - color: widget.isDashboardInfo ? Colors.grey : Colors.grey.shade300, - width: 125, child: Icon(Icons.info, color: Colors.white)) + color: widget.isDashboardInfo ? Colors.grey : widget.dashboard.midDashColor, + width: 200 / 2, child: Icon(Icons.info, color: Colors.white)) ) ), Tooltip( @@ -580,8 +580,8 @@ class FlowChartSelectedMenuState extends State { mouseCursor: SystemMouseCursors.click, child: Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 10), - color: !widget.isDashboardInfo ? Colors.grey : Colors.grey.shade300, - width: 125, child: Icon(Icons.format_paint, color: Colors.white)), + color: !widget.isDashboardInfo ? Colors.grey : widget.dashboard.midDashColor, + width: 200 / 2, child: Icon(Icons.format_paint, color: Colors.white)), )) ])), w diff --git a/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart b/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart index 8baa579..33a3410 100755 --- a/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart +++ b/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart @@ -390,7 +390,7 @@ class GraphParamsWidgetState extends State { child: Row(children: [ IconButton(onPressed: () { widget.comp.setState(() { - widget.comp.widget.dashboard.arrows.removeWhere((el) => el.fromID == "${widget.element.id}${widget.index}"); + widget.comp.widget.dashboard.removeArrows((el) => el.fromID == "${widget.element.id}${widget.index}"); widget.element.next.removeAt(widget.index); }); }, icon: Icon(Icons.delete)) @@ -399,17 +399,18 @@ class GraphParamsWidgetState extends State { } class ArrowInfoWidget extends StatefulWidget { - ArrowInfoWidget ({ Key? key, }): super(key: key); + Dashboard dashboard; + ArrowInfoWidget ({ Key? key, required this.dashboard }): super(key: key); @override ArrowInfoWidgetState createState() => ArrowInfoWidgetState(); } class ArrowInfoWidgetState extends State { @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column(children: [ Container(height: 50, - decoration: BoxDecoration(color: Colors.grey.shade300, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), + decoration: BoxDecoration(color: widget.dashboard.midDashColor, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Center( child: Text(" Style", style: TextStyle(fontSize: 20)))), Container(height: 50, - decoration: BoxDecoration(color: Colors.grey.shade300, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), + decoration: BoxDecoration(color: widget.dashboard.midDashColor, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Row(children: [],) ), ],) ); @@ -731,8 +732,8 @@ class ArrowPainter extends CustomPainter { bool isLine(Offset position) { - for (double i=-20; i < 20; i++) { - for (double y=-20; y < 20; y++) { + for (double i=-5; i < 5; i++) { + for (double y=-5; y < 5; y++) { var pos = position + Offset(i, y); if (path.contains(pos)) { return true; diff --git a/library/flutter_flow_chart/lib/src/ui/element_handlers.dart b/library/flutter_flow_chart/lib/src/ui/element_handlers.dart index e97f936..19ebda4 100755 --- a/library/flutter_flow_chart/lib/src/ui/element_handlers.dart +++ b/library/flutter_flow_chart/lib/src/ui/element_handlers.dart @@ -210,7 +210,7 @@ class _ElementHandler extends StatelessWidget { }, child: GestureDetector( onTapDown: (details) => - tapDown = details.globalPosition - dashboard.position, + tapDown = details.globalPosition - dashboard.position , onSecondaryTapDown: (details) => secondaryTapDown = details.globalPosition - dashboard.position, onTap: () { @@ -266,10 +266,10 @@ class _ElementHandler extends StatelessWidget { forwardWidth: dashboard.defaultForwardWidth, ); DrawingArrow.instance.from = - details.globalPosition - Offset(-10, 45); + details.globalPosition - Offset(dashboard.widthOffset - 10, 45 + dashboard.heightOffset); // todo change isDragging = true; } - DrawingArrow.instance.to = details.globalPosition - Offset(-10, 50); + DrawingArrow.instance.to = details.globalPosition - Offset(dashboard.widthOffset - 10, 50 + dashboard.heightOffset); // todo change DrawingArrow.instance.setParams( DrawingArrow.instance.params.copyWith( endArrowPosition: Alignment.center, diff --git a/library/flutter_flow_chart/lib/src/ui/element_widget.dart b/library/flutter_flow_chart/lib/src/ui/element_widget.dart index 8282122..554533e 100755 --- a/library/flutter_flow_chart/lib/src/ui/element_widget.dart +++ b/library/flutter_flow_chart/lib/src/ui/element_widget.dart @@ -13,11 +13,19 @@ 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 { + Widget? bottomLeftBadge; + Widget? bottomRightBadge; + Widget? topLeftBadge; + Widget? topRightBadge; /// ElementWidget({ required this.dashboard, required this.element, super.key, + this.bottomLeftBadge, + this.bottomRightBadge, + this.topLeftBadge, + this.topRightBadge, this.onElementPressed, this.onElementSecondaryTapped, this.onElementLongPressed, @@ -27,7 +35,7 @@ class ElementWidget extends StatefulWidget { this.onHandlerLongPressed, this.onHandlerSecondaryLongTapped, }); - + Color? dashColor; /// final Dashboard dashboard; @@ -153,8 +161,7 @@ class ElementWidgetState extends State { widget.onElementLongPressed?.call(context, tapLocation); }, onSecondaryLongPress: () { - widget.onElementSecondaryLongTapped - ?.call(context, secondaryTapDownPos); + widget.onElementSecondaryLongTapped?.call(context, secondaryTapDownPos); }, child: Listener( onPointerDown: (event) { @@ -168,8 +175,7 @@ class ElementWidgetState extends State { color: Colors.transparent, child: Padding( padding: EdgeInsets.all(6), child: Container( - decoration: BoxDecoration(border: Border.all( - color: Colors.red, width: 2)), + decoration: BoxDecoration(border: Border.all( color: Colors.red, width: 2)), width: widget.element.size.width - 12, height: widget.element.size.height - 12, child: element) ), @@ -183,9 +189,9 @@ class ElementWidgetState extends State { onHandlerLongPressed: widget.onHandlerLongPressed, onHandlerSecondaryLongTapped: widget.onHandlerSecondaryLongTapped, child: Container( - margin: EdgeInsets.all(6), + margin: EdgeInsets.all(10), // why some change decoration: BoxDecoration( - border: Border.all(color: widget.element.isSelected ? Colors.red : Colors.grey.shade300, + border: Border.all(color: widget.element.isSelected ? Colors.red : widget.dashboard.midDashColor, width: widget.element.isSelected ? 2 : 1), ), child: InkWell( mouseCursor: SystemMouseCursors.grab, child: element ) @@ -199,7 +205,8 @@ class ElementWidgetState extends State { var diff = Offset(widget.element.position.dx, widget.element.position.dy); widget.element.isSelected = true; widget.element.changePosition( - details.globalPosition - delta - Offset(0, 50), + details.globalPosition - delta - Offset( + widget.dashboard.widthOffset, 50 + widget.dashboard.heightOffset), // todo change ); diff = widget.element.position - diff; if (widget.element.isSelected) { @@ -211,7 +218,9 @@ class ElementWidgetState extends State { }, onDragEnd: (details) { var diff = Offset(widget.element.position.dx, widget.element.position.dy); - widget.element.changePosition(details.offset - Offset(0, 50)); + widget.element.changePosition(details.offset - Offset( + widget.dashboard.widthOffset, 50 + widget.dashboard.heightOffset + )); // todo change diff = widget.element.position - diff; if (widget.element.isSelected) { for (var sel in widget.dashboard.elementSelected) { @@ -226,9 +235,13 @@ class ElementWidgetState extends State { ); w = ResizeWidget( comp: this, + bottomLeftBadge: widget.bottomLeftBadge, + bottomRightBadge: widget.bottomRightBadge, + topLeftBadge: widget.topLeftBadge, + topRightBadge: widget.topRightBadge, element: widget.element, dashboard: widget.dashboard, - handlerColor: widget.isHovered ? Color.fromRGBO(38, 166, 154, 1) : Colors.transparent, + handlerColor: widget.isHovered ? widget.dashboard.dashColor : Colors.transparent, child: w ); return Transform.translate( @@ -237,8 +250,8 @@ class ElementWidgetState extends State { child: MouseRegion( onEnter: (event) { setState(() { widget.isHovered = true; }); }, onExit: (event) { setState(() { widget.isHovered = false; }); }, - child: Wrap( direction: Axis.vertical, children: [ - w, + child: Wrap( direction: Axis.vertical, children: [ + w, Container( constraints: BoxConstraints( minWidth: widget.element.size.width ), child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -258,7 +271,7 @@ class ElementWidgetState extends State { widget.dashboard.addElement(newElement); }, icon: Icon(Icons.copy, size: 20)), ])) - ) + ), ]) ) ); diff --git a/library/flutter_flow_chart/lib/src/ui/resize_widget.dart b/library/flutter_flow_chart/lib/src/ui/resize_widget.dart index 7bf7155..a2bcbcc 100644 --- a/library/flutter_flow_chart/lib/src/ui/resize_widget.dart +++ b/library/flutter_flow_chart/lib/src/ui/resize_widget.dart @@ -5,15 +5,21 @@ import 'package:flutter_flow_chart/src/ui/handler_widget.dart'; /// The widget to press and drag to resize the element class ResizeWidget extends StatefulWidget { + Widget? bottomLeftBadge; + Widget? bottomRightBadge; + Widget? topLeftBadge; + Widget? topRightBadge; /// ResizeWidget({ required this.comp, required this.element, required this.dashboard, required this.child, + this.bottomLeftBadge, + this.bottomRightBadge, + this.topLeftBadge, + this.topRightBadge, this.handlerColor =const Color.fromRGBO(38, 166, 154, 1), - this.additionnalHeight = 0, - super.key, }); @@ -27,10 +33,6 @@ class ResizeWidget extends StatefulWidget { /// final Widget child; - - /// - final double additionnalHeight; - @override State createState() => _ResizeWidgetState(); } @@ -40,12 +42,16 @@ class _ResizeWidgetState extends State { late Offset elementStartPosition; @override Widget build(BuildContext context) { - return SizedBox( + return Container( width: widget.element.size.width, - height: widget.element.size.height + widget.additionnalHeight, + height: widget.element.size.height, child: Stack( children: [ widget.child, + widget.topLeftBadge == null ? Container() : Positioned(top: 0, left: 0, child: widget.topLeftBadge!), + widget.topRightBadge == null ? Container() : Positioned(top: 0, right: 0, child: widget.topRightBadge!), + widget.bottomRightBadge == null ? Container() : Positioned(bottom: 0, right: 0, child: widget.bottomRightBadge!), + widget.bottomLeftBadge == null ? Container() : Positioned(bottom: 0, left: 0, child: widget.bottomLeftBadge!), _handler(Alignment.topLeft), _handler(Alignment.topRight), _handler(Alignment.bottomLeft), diff --git a/library/flutter_flow_chart/lib/src/ui/segment_handler.dart b/library/flutter_flow_chart/lib/src/ui/segment_handler.dart index 2297fb1..9b0a20d 100755 --- a/library/flutter_flow_chart/lib/src/ui/segment_handler.dart +++ b/library/flutter_flow_chart/lib/src/ui/segment_handler.dart @@ -63,7 +63,6 @@ class _SegmentHandlerState extends State { }, onDragEnd: (details) { widget.pivot.pivot = details.offset; - }, child: GestureDetector( onTap: () { diff --git a/local_run.sh b/local_run.sh index 0ad8c1e..ab102d2 100755 --- a/local_run.sh +++ b/local_run.sh @@ -5,7 +5,8 @@ WORKFLOW_HOST='http://localhost:8088/oc' ITEM_HOST='http://localhost:8087/oc' SCHEDULER_HOST='http://localhost:8090/oc' LOGS_HOST='http://localhost:3100' -PEER_HOST='http://localhost:8091/oc' -COLLABORATIVE_AREA_HOST='http://localhost:8094/oc' +PEER_HOST='http://localhost:8093/oc' +COLLABORATIVE_AREA_HOST='http://localhost:8091/oc' +AUTH_HOST='http://localhost:8094/oc' -flutter run -d linux --dart-define=WORKSPACE_HOST=$WORKSPACE_HOST --dart-define=WORKFLOW_HOST=$WORKFLOW_HOST --dart-define=PEER_HOST=$PEER_HOST --dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST --dart-define=LOGS_HOST=$LOGS_HOST --dart-define=ITEM_HOST=$ITEM_HOST \ No newline at end of file +flutter run -d linux --dart-define=AUTH_HOST=$AUTH_HOST --dart-define=WORKSPACE_HOST=$WORKSPACE_HOST --dart-define=WORKFLOW_HOST=$WORKFLOW_HOST --dart-define=PEER_HOST=$PEER_HOST --dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST --dart-define=LOGS_HOST=$LOGS_HOST --dart-define=ITEM_HOST=$ITEM_HOST \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 806dd74..7001553 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,18 +13,18 @@ packages: dependency: "direct main" description: name: animated_toggle_switch - sha256: "35e3d6c74eef79c415ac3986046c35cb1ea42720afce13ec7f1a014f72dfd71c" + sha256: "786e82be3b004100299c1c6d023f8f1928decc8353a6fdff191bf78c866262fa" url: "https://pub.dev" source: hosted - version: "0.8.2" + version: "0.8.3" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" async: dependency: transitive description: @@ -133,58 +133,58 @@ packages: dependency: "direct main" description: name: desktop_window - sha256: "6256fb6feb7b5ec1311c76a3503f89202825bfe92c0458ec5fe7a728ffa216d5" + sha256: cb30b3bcea10931a21333ed044f85054cf9242820f3c240264a4c0df324a9fd6 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.1" device_info_plus: dependency: transitive description: name: device_info_plus - sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91 + sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 url: "https://pub.dev" source: hosted - version: "10.1.0" + version: "10.1.2" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 + sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" dio: dependency: "direct main" description: name: dio - sha256: "77befdddf51050e1635a04d2bcfff230089ce7294e642d00da58cd079c0de0c8" + sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.7.0" dio_web_adapter: dependency: transitive description: name: dio_web_adapter - sha256: "36c5b2d79eb17cdae41e974b7a8284fec631651d2a6f39a8a2ff22327e90aeac" + sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "2.0.0" dotted_line: dependency: "direct main" description: name: dotted_line - sha256: c931ba331656154711d9420f369f80cf9e8869ca9933ae5fb35b7669bcbe7d2e + sha256: "41e3d655939559815daa1370fc1e07673a205fa628cf40ce3af45d90029a77b6" url: "https://pub.dev" source: hosted - version: "3.2.2" + version: "3.2.3" el_tooltip: dependency: "direct main" description: name: el_tooltip - sha256: bdaa31ae3c925a50a1448fca79f7264204d29310e8cc5312425ec1aadb1c7026 + sha256: "0860b00e9390a31dd98369dc16d3b6fa2668fc52df712bd00e86d8931787fc17" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.2.1" fake_async: dependency: transitive description: @@ -197,26 +197,26 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -234,10 +234,10 @@ packages: dependency: "direct main" description: name: flutter_box_transform - sha256: "2b844096d2cb14b7d9444abc972aa57233c0eeab92ca60c92b8211b49c103158" + sha256: "428619d0ea67631e4486b7a2ba46b1f6589420dcb9d0e520f8c81b98bd211159" url: "https://pub.dev" source: hosted - version: "0.4.4" + version: "0.4.6" flutter_colorpicker: dependency: "direct main" description: @@ -265,10 +265,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "5.0.0" flutter_map: dependency: "direct main" description: @@ -303,6 +303,14 @@ packages: description: flutter source: sdk version: "0.0.0" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a + url: "https://pub.dev" + source: hosted + version: "10.8.0" get_it: dependency: transitive description: @@ -315,10 +323,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: cdae1b9c8bd7efadcef6112e81c903662ef2ce105cbd220a04bbb7c3425b5554 + sha256: "6f1b756f6e863259a99135ff3c95026c3cdca17d10ebef2bba2261a25ddc8bbc" url: "https://pub.dev" source: hosted - version: "14.2.0" + version: "14.3.0" hover_menu: dependency: "direct main" description: @@ -331,10 +339,10 @@ packages: dependency: transitive description: name: http - sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" http_parser: dependency: transitive description: @@ -403,34 +411,34 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "5.0.0" lists: dependency: transitive description: @@ -439,14 +447,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + localstorage: + dependency: "direct main" + description: + name: localstorage + sha256: "6340acefdd3a969cceb044a69cde2dc5877c5b861b2e02d0803930ed483dbe91" + url: "https://pub.dev" + source: hosted + version: "5.0.0" logger: dependency: transitive description: name: logger - sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4 + sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" logging: dependency: transitive description: @@ -467,18 +483,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mgrs_dart: dependency: transitive description: @@ -515,10 +531,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" path_provider_android: dependency: transitive description: @@ -555,10 +571,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -579,10 +595,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -643,42 +659,42 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" + sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.5.3" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.1" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" simple_gesture_detector: dependency: transitive description: @@ -744,50 +760,50 @@ packages: dependency: transitive description: name: super_clipboard - sha256: cdab725bac26655ebd189f4d202d694a8cbc1c21e0f0478ccd7829c71716f09b + sha256: "74098001413e075cc53dee72b68c32eaffc10709df41806800393abaa6dac9d5" url: "https://pub.dev" source: hosted - version: "0.8.17" + version: "0.8.19" super_drag_and_drop: dependency: "direct main" description: name: super_drag_and_drop - sha256: "8e00c6082646076f80b972b39d9c27b5311082ea1e8add5fa370ce11c410f7de" + sha256: "20f4318a6c9e81a76cc090a0f2d845157ff4f3619ed784e3235324a45ce34507" url: "https://pub.dev" source: hosted - version: "0.8.17" + version: "0.8.19" super_native_extensions: dependency: transitive description: name: super_native_extensions - sha256: fa55d452d34b7112453afbb9fa4d13c0527ff201630d10d86546497179030544 + sha256: c24676825c9f3ae844676a843d45ad186f2270539ffe72be4277753e46d14e29 url: "https://pub.dev" source: hosted - version: "0.8.17" + version: "0.8.19" syncfusion_flutter_calendar: dependency: "direct main" description: name: syncfusion_flutter_calendar - sha256: "1daa6077a8fb388b692d5d050d58eaa4c01ef92f064a882eb330ef47dc51cf2e" + sha256: "1fdbcb8435abc4a1fb36914b83d9690eb0dea617df3ac2772519fba7a3011828" url: "https://pub.dev" source: hosted - version: "26.2.7" + version: "27.1.55" syncfusion_flutter_core: dependency: transitive description: name: syncfusion_flutter_core - sha256: fd4d2cdbf8d0d1e3441817cb8a03f896566fad5187788957e78492fe16800388 + sha256: bc86234c9a0a87b6c3288b9065175e74e9a73e22b2237989a8bbdeff0c8befd7 url: "https://pub.dev" source: hosted - version: "26.2.7" + version: "27.1.55" syncfusion_flutter_datepicker: dependency: transitive description: name: syncfusion_flutter_datepicker - sha256: e541929ccf95a9188ef9f32dfca544f29b3fc222d4dc5da9cb1112305021a615 + sha256: "54fe7e7a660ecdf072cceec890425d7531b42f647245f9244565c61e96fbca4a" url: "https://pub.dev" source: hosted - version: "26.2.7" + version: "27.1.55" table_calendar: dependency: "direct main" description: @@ -808,18 +824,18 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" timezone: dependency: transitive description: name: timezone - sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5 + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" url: "https://pub.dev" source: hosted - version: "0.9.3" + version: "0.9.4" typed_data: dependency: transitive description: @@ -840,10 +856,10 @@ packages: dependency: "direct main" description: name: uuid - sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.5.1" vector_graphics: dependency: transitive description: @@ -880,10 +896,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.5" web: dependency: transitive description: @@ -892,46 +908,14 @@ 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: name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" + sha256: e1d0cc62e65dc2561f5071fcbccecf58ff20c344f8f3dc7d4922df372a11df1f url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.7.1" win32_registry: dependency: transitive description: @@ -952,10 +936,10 @@ packages: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" xml: dependency: transitive description: @@ -965,5 +949,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.3.4 <=3.7.12" + dart: ">=3.5.0 <=3.7.12" flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index dc56330..568ee0d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,13 +66,12 @@ dependencies: 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 + syncfusion_flutter_calendar: ^27.1.55 json_string: ^3.0.1 flutter_spinkit: ^5.2.1 - + localstorage: ^5.0.0 + font_awesome_flutter: ^10.8.0 + dev_dependencies: flutter_test: sdk: flutter @@ -82,7 +81,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^3.0.0 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec