diff --git a/Dockerfile b/Dockerfile index 28d8f9b..004f867 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,8 +13,9 @@ ARG LOGS_HOST="http://localhost:3100" ARG PEER_HOST="http://localhost:8093/oc" ARG DATACENTER_HOST="http://localhost:8092/oc" ARG COLLABORATIVE_AREA_HOST="http://localhost:8091/oc" +ARG AUTH_MODE=true # define variables -ARG FLUTTER_SDK=/usr/local/flutter +ARG FLUTTER_SDK=/usr/local/flutter ARG FLUTTER_VERSION=3.19.6 ARG APP=/app/ @@ -41,6 +42,7 @@ WORKDIR $APP RUN flutter clean RUN flutter pub get RUN flutter build web \ + --dart-define=AUTH_MODE=$AUTH_MODE \ --dart-define=WORKSPACE_HOST=$WORKSPACE_HOST \ --dart-define=WORKFLOW_HOST=$WORKFLOW_HOST \ --dart-define=PEER_HOST=$PEER_HOST \ diff --git a/lib/core/models/shared_workspace_local.dart b/lib/core/models/shared_workspace_local.dart index e2e898e..28e7b5e 100644 --- a/lib/core/models/shared_workspace_local.dart +++ b/lib/core/models/shared_workspace_local.dart @@ -18,8 +18,8 @@ class CollaborativeAreaLocal { static Map workspaces = {}; static final SharedService _service = SharedService(); - static void init(BuildContext context, bool changeCurrent) { - _service.all(context).then((value) { + static Future init(BuildContext context, bool changeCurrent) async { + await _service.all(context).then((value) { if (value.data != null && value.data!.values.isNotEmpty ) { var vals = value.data!.values; for (var element in vals) { diff --git a/lib/core/sections/header/header.dart b/lib/core/sections/header/header.dart index 68c3028..482a131 100644 --- a/lib/core/sections/header/header.dart +++ b/lib/core/sections/header/header.dart @@ -68,7 +68,7 @@ class HeaderWidgetState extends State { if (AppRouter.currentRoute.factory.searchFill()) { return DefaultWidget(); } - HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) || AppRouter.currentRoute.factory.searchFill() ? 50 : 100; + HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) || !AppRouter.currentRoute.factory.searchFill() ? 50 : 100; return Column( children: [ AppRouter.currentRoute.factory.searchFill() ? Container() : Container( height: 50, width: getMainWidth(context), diff --git a/lib/core/sections/header/menu.dart b/lib/core/sections/header/menu.dart index 7c1711f..6b71ac4 100644 --- a/lib/core/sections/header/menu.dart +++ b/lib/core/sections/header/menu.dart @@ -21,12 +21,15 @@ class HeaderMenuWidgetState extends State { border: Border(bottom: BorderSide(color: midColor)) ), 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'))), + AppRouter.currentRoute.factory.searchFill() ? Container() : Positioned( top: 0, left: 30, + child: InkWell( onTap: () { + AppRouter.zones.first.go(context, {}); + }, + child: Wrap( alignment: WrapAlignment.center, children: [ + SvgPicture.asset("assets/images/icon.svg", width: 70, height: 70, semanticsLabel: 'OpenCloud Logo'), + Container( height: 50, alignment: Alignment.centerLeft, margin: const EdgeInsets.only(left: 20), + child: Text(AppRouter.currentRoute.label ?? "Where am I ?", style: TextStyle( color: Colors.grey))) + ]))), Padding( padding: const EdgeInsets.only(left: 50), child: Row(crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.end, diff --git a/lib/core/services/auth.service.dart b/lib/core/services/auth.service.dart index 8c3b308..aef1371 100644 --- a/lib/core/services/auth.service.dart +++ b/lib/core/services/auth.service.dart @@ -2,12 +2,18 @@ import 'package:localstorage/localstorage.dart'; import 'package:oc_front/core/sections/header/header.dart'; import 'package:oc_front/core/services/api_service.dart'; +import 'package:oc_front/core/services/perms_service.dart'; import 'package:oc_front/models/response.dart'; class AuthService { + static var isAuth = const bool.fromEnvironment('AUTH_MODE', defaultValue: false); static APIService service = APIService( baseURL: const String.fromEnvironment('AUTH_HOST', defaultValue: 'http://localhost:8080/auth'), ); static Future init() async { + if (!isAuth) { + return; + } + PermsService.init(localStorage.getItem('accessToken') ?? ""); bool ok = await introspect().catchError( (e) => false ); if (ok) { var now = DateTime.now(); @@ -22,11 +28,17 @@ class AuthService { } static bool isConnected() { + if (!isAuth) { + return true; + } return (localStorage.getItem('accessToken') ?? "") != ""; } static String? getUsername() { - return localStorage.getItem('username'); + if (!isAuth) { + return "no auth user"; + } + return localStorage.getItem('username') ?? "unknown"; } static Future login(String username, String password) async { @@ -41,6 +53,7 @@ class AuthService { localStorage.setItem('expiresIn', DateTime.now().add(Duration(seconds: token.data?.value['expires_in'])).toIso8601String()); HeaderConstants.headerKey.currentState?.setState(() {}); + PermsService.init(token.data?.value['access_token']); refresh(token.data?.value['access_token'] ?? "", username, Duration(seconds: token.data?.value['expires_in'])); } } @@ -51,6 +64,7 @@ class AuthService { localStorage.setItem('accessToken', ''); localStorage.setItem('username', ''); localStorage.setItem('expiresIn', ''); + PermsService.clear(); } } @@ -69,6 +83,7 @@ class AuthService { "username": username }, null).then((token) { if (token.code == 200 && token.data != null) { + PermsService.init(token.data?.value['access_token']); localStorage.setItem('accessToken', token.data?.value['access_token']); localStorage.setItem('username', username); localStorage.setItem('expiresIn', diff --git a/lib/core/services/perms_service.dart b/lib/core/services/perms_service.dart index 33b200a..48e4213 100644 --- a/lib/core/services/perms_service.dart +++ b/lib/core/services/perms_service.dart @@ -1,14 +1,21 @@ +import 'dart:convert'; + enum Perms { SEARCH_INTERNAL,// ignore: constant_identifier_names SEARCH_EXTERNAL, // ignore: constant_identifier_names WORKSPACE_SHARE,// ignore: constant_identifier_names + WORKSPACE_UNSHARE,// ignore: constant_identifier_names WORKFLOW_CREATE, // ignore: constant_identifier_names WORKFLOW_EDIT, // ignore: constant_identifier_names WORKFLOW_DELETE, // ignore: constant_identifier_names WORKFLOW_BOOKING, // ignore: constant_identifier_names WORKFLOW_SHARE, // ignore: constant_identifier_names + WORKFLOW_UNSHARE, // ignore: constant_identifier_names + + PEER_SHARE, // ignore: constant_identifier_names + PEER_UNSHARE, // ignore: constant_identifier_names COLLABORATIVE_AREA_CREATE, // ignore: constant_identifier_names COLLABORATIVE_AREA_EDIT, // ignore: constant_identifier_names @@ -16,35 +23,77 @@ enum Perms { } 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', + Perms.SEARCH_INTERNAL: 'GET__catalog_compute_search_search'.toUpperCase(), + Perms.SEARCH_EXTERNAL: 'Search External'.toUpperCase(), + Perms.WORKSPACE_SHARE: 'POST__shared_collaborative_area_id_workspace_id2'.toUpperCase(), + Perms.WORKFLOW_CREATE: 'POST__workflow_'.toUpperCase(), + Perms.WORKFLOW_UNSHARE: 'DELETE__shared_collaborative_area_id_workflow_id2'.toUpperCase(), + Perms.PEER_SHARE: 'POST__shared_collaborative_area_id_peer_id2'.toUpperCase(), + Perms.PEER_UNSHARE: 'DELETE__shared_collaborative_area_id_peer_id2'.toUpperCase(), + Perms.COLLABORATIVE_AREA_CREATE: 'POST__shared_collaborative_area_'.toUpperCase(), + Perms.COLLABORATIVE_AREA_EDIT: 'PUT__shared_collaborative_area_id'.toUpperCase(), + Perms.COLLABORATIVE_AREA_DELETE: 'DELETE__shared_collaborative_area_id'.toUpperCase(), + Perms.WORKSPACE_UNSHARE: 'DELETE__shared_collaborative_area_id_workspace_id2'.toUpperCase(), + Perms.WORKFLOW_EDIT: 'PUT__workflow_id'.toUpperCase(), + Perms.WORKFLOW_DELETE: 'DELETE__workflow_id'.toUpperCase(), + Perms.WORKFLOW_BOOKING: 'POST__datacenter_booking_'.toUpperCase(), + Perms.WORKFLOW_SHARE: 'POST__shared_collaborative_area_id_workflow_id2'.toUpperCase(), }; class PermsService { - static const Map _perms = { + static final Map _perms = { Perms.SEARCH_INTERNAL: true, Perms.SEARCH_EXTERNAL: true, Perms.WORKSPACE_SHARE: true, + Perms.WORKSPACE_UNSHARE: true, Perms.WORKFLOW_CREATE: true, Perms.WORKFLOW_EDIT: true, Perms.WORKFLOW_DELETE: true, Perms.WORKFLOW_BOOKING: true, Perms.WORKFLOW_SHARE: true, - + Perms.WORKFLOW_UNSHARE: true, + Perms.PEER_SHARE: true, + Perms.PEER_UNSHARE: true, Perms.COLLABORATIVE_AREA_CREATE: true, - Perms.COLLABORATIVE_AREA_EDIT: false, - Perms.COLLABORATIVE_AREA_DELETE: false, + Perms.COLLABORATIVE_AREA_EDIT: true, + Perms.COLLABORATIVE_AREA_DELETE: true, }; static final PermsService _instance = PermsService._internal(); factory PermsService() => _instance; PermsService._internal(); + /* should decode claims such as in oc-auth */ + static Future init(String token ) async { +/* var claims = token.split(".").last; + var decoded = base64.decode(claims); + String foo = utf8.decode(decoded); + var what = json.decode(foo); + try { + what = what["session"]["access_token"] as Map; + for (var w in perms.values) { + + if (what.keys.contains(w)) { + print("CONTAINS"); + } else { + for (var y in what.keys) { + print("${w}, ${y} ${what.keys.contains(w)}"); + } + } + } + } catch (e) { + print("THERE"); + }*/ + + _perms.forEach((key, value) { + _perms[key] = true; + }); + } + + static void clear() { + _perms.forEach((key, value) { + _perms[key] = false; + }); + } static bool getPerm(Perms perm) { return _perms[perm] ?? false; } diff --git a/lib/models/search.dart b/lib/models/search.dart index 55fff55..bad965a 100644 --- a/lib/models/search.dart +++ b/lib/models/search.dart @@ -114,6 +114,10 @@ abstract class AbstractItem extends FlowData implements Seri @override String getName() { return name ?? ""; } + + String getTopic() { + return topic; + } } class Model extends SerializerDeserializer { @@ -288,6 +292,11 @@ class Containered extends SerializerDeserializer { } class ProcessingItem extends SerializerDeserializer implements AbstractItem { + @override + String getTopic() { + return topic; + } + ProcessingItem({ this.id, this.name, @@ -448,6 +457,11 @@ class ProcessingItem extends SerializerDeserializer implements A } class WorkflowItem extends SerializerDeserializer implements AbstractItem { + @override + String getTopic() { + return topic; + } + WorkflowItem({ this.id, this.name, @@ -571,6 +585,10 @@ class WorkflowItem extends SerializerDeserializer implements Abstr } class DataItem extends SerializerDeserializer implements AbstractItem { + @override + String getTopic() { + return topic; + } DataItem({ this.id, this.name, @@ -711,6 +729,11 @@ class DataItem extends SerializerDeserializer implements AbstractItem< } class ComputeItem extends SerializerDeserializer implements AbstractItem { + @override + String getTopic() { + return topic; + } + ComputeItem({ this.id, this.name, @@ -962,6 +985,11 @@ class RAM extends SerializerDeserializer { }; } class StorageItem extends SerializerDeserializer implements AbstractItem { + @override + String getTopic() { + return topic; + } + StorageItem({ this.id, this.name, diff --git a/lib/models/shared.dart b/lib/models/shared.dart index 341f967..ce4e11c 100644 --- a/lib/models/shared.dart +++ b/lib/models/shared.dart @@ -3,6 +3,48 @@ import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/models/workspace.dart'; +/* + based on : + type CollaborativeAreaRule struct { + ShareMode string `json:"share_mode,omitempty" bson:"share_mode,omitempty"` // Share is the share of the rule + CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` // CreatedAt is the time the rule was created + Creator string `json:"creator,omitempty" bson:"creator,omitempty"` // Creator is the creator of the rule + ExploitedBy string `json:"exploited_by,omitempty" bson:"exploited_by,omitempty"` // ExploitedBy is the exploited by of the rule +} +*/ +class CollaborativeAreaRule extends SerializerDeserializer { + String? shareMode; + DateTime? createdAt; + String? creator; + String? exploitedBy; + + CollaborativeAreaRule( + {this.shareMode, + this.createdAt, + this.creator, + this.exploitedBy,}); + + @override + CollaborativeAreaRule deserialize(dynamic json) { + try { json = json as Map; + } catch (e) { return CollaborativeAreaRule(); } + return CollaborativeAreaRule( + shareMode: json.containsKey("share_mode") ? json["share_mode"] : null, + createdAt: json.containsKey("created_at") ? DateTime.parse(json["created_at"]) : null, + creator: json.containsKey("creator") ? json["creator"] : null, + exploitedBy: json.containsKey("exploited_by") ? json["exploited_by"] : null, + ); + } + + @override + Map serialize() => { + "share_mode": shareMode, + "created_at": createdAt?.toIso8601String(), + "creator": creator, + "exploited_by": exploitedBy, + }; +} + class CollaborativeArea extends SerializerDeserializer { String? id; String? name; @@ -14,6 +56,7 @@ class CollaborativeArea extends SerializerDeserializer { List workflows = []; List peers = []; List rules = []; + CollaborativeAreaRule? rule; CollaborativeArea( {this.id, @@ -25,6 +68,7 @@ class CollaborativeArea extends SerializerDeserializer { this.workspaces = const [], this.workflows = const [], this.peers = const [], + this.rule, this.rules = const []}); @override @@ -32,10 +76,10 @@ class CollaborativeArea extends SerializerDeserializer { try { json = json as Map; } catch (e) { return CollaborativeArea(); } return CollaborativeArea( + rule : json.containsKey("collaborative_area") ? CollaborativeAreaRule().deserialize(json["collaborative_area"]) : CollaborativeAreaRule(), id: json.containsKey("id") ? json["id"] : null, name: json.containsKey("name") ? json["name"] : null, description: json.containsKey("description") ? json["description"] : null, - creatorID: json.containsKey("peer_id") ? json["peer_id"] : null, version: json.containsKey("version") ? json["version"] : null, attributes: json.containsKey("attributes") ? json["attributes"] : {}, workspaces: json.containsKey("shared_workspaces") ? fromListJson(json["shared_workspaces"], Workspace()) : [], @@ -52,6 +96,7 @@ class CollaborativeArea extends SerializerDeserializer { "creator_id": creatorID, "version": version, "attributes": attributes, + "rule": rule?.serialize(), "workspaces": workspaces.map((e) => e.id).toList(), "workflows": workflows.map((e) => e.id).toList(), "peers": peers.map((e) => e.id).toList(), diff --git a/lib/pages/abstract_page.dart b/lib/pages/abstract_page.dart index d65b56c..eefc6ea 100644 --- a/lib/pages/abstract_page.dart +++ b/lib/pages/abstract_page.dart @@ -6,5 +6,4 @@ abstract class AbstractFactory { Widget factory(GoRouterState state, List args); bool searchFill(); 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 ab42da2..7c19372 100644 --- a/lib/pages/catalog.dart +++ b/lib/pages/catalog.dart @@ -10,13 +10,6 @@ import 'package:oc_front/pages/abstract_page.dart'; class CatalogFactory implements AbstractFactory { @override GlobalKey getKey() { return key; } static GlobalKey key = GlobalKey(); - @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, bool special) { @@ -46,9 +39,8 @@ class CatalogPageWidgetState extends State { @override Widget build(BuildContext context) { if (widget.items.isEmpty) { return Container(); } return Column( children : [ - SizedBox( - width: getMainWidth(context), - height: getMainHeight(context), + SizedBox( width: getMainWidth(context), + height: getMainHeight(context) - 50, child: SingleChildScrollView( child: CatalogWidget(items: CatalogFactory.key.currentState?.widget.items, itemWidth: widget.itemWidth) )), ] ); diff --git a/lib/pages/catalog_item.dart b/lib/pages/catalog_item.dart index 7b5f1ff..acaf8c6 100644 --- a/lib/pages/catalog_item.dart +++ b/lib/pages/catalog_item.dart @@ -10,7 +10,6 @@ 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) { diff --git a/lib/pages/datacenter.dart b/lib/pages/datacenter.dart index 266a357..c3bce47 100644 --- a/lib/pages/datacenter.dart +++ b/lib/pages/datacenter.dart @@ -10,7 +10,6 @@ import 'package:oc_front/widgets/sheduler_items/schedule.dart'; class DatacenterFactory 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 ComputePageWidget(); } @@ -30,7 +29,7 @@ class ComputePageWidget extends StatefulWidget { } class ComputePageWidgetState extends State { List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "MISSED"]; @override Widget build(BuildContext context) { return FutureBuilder( diff --git a/lib/pages/map.dart b/lib/pages/map.dart index 7a32169..0112b9a 100644 --- a/lib/pages/map.dart +++ b/lib/pages/map.dart @@ -6,7 +6,6 @@ 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(); } diff --git a/lib/pages/scheduler.dart b/lib/pages/scheduler.dart index 2712fa2..5199632 100644 --- a/lib/pages/scheduler.dart +++ b/lib/pages/scheduler.dart @@ -11,7 +11,6 @@ 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(); } @@ -30,7 +29,7 @@ class SchedulerPageWidget extends StatefulWidget { } class SchedulerPageWidgetState extends State { List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "MISSED"]; @override Widget build(BuildContext context) { return FutureBuilder( diff --git a/lib/pages/shared.dart b/lib/pages/shared.dart index 57af466..5b63c01 100644 --- a/lib/pages/shared.dart +++ b/lib/pages/shared.dart @@ -1,7 +1,9 @@ import 'dart:async'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:intl/intl.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'; @@ -12,7 +14,9 @@ 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/search.dart'; import 'package:oc_front/models/shared.dart'; +import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/abstract_page.dart'; import 'package:oc_front/widgets/catalog.dart'; import 'package:oc_front/widgets/dialog/shallow_creation.dart'; @@ -24,7 +28,6 @@ enum CollaborativeAreaType { global, collaborative_area, workspace, workflow, pe 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(); } @@ -134,14 +137,16 @@ class SharedPageWidgetState extends State { 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 { + load: PermsService.getPerm(Perms.WORKSPACE_SHARE) ? (String val) async { await service.addWorkspace(context, CollaborativeAreaLocal.current ?? "", val); - CollaborativeAreaLocal.init(context, false); - }, - remove: (String val) async { + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : null, + remove: PermsService.getPerm(Perms.WORKSPACE_UNSHARE) ? (String val) async { await service.removeWorkspace(context, CollaborativeAreaLocal.current ?? "", val); - CollaborativeAreaLocal.init(context, false); - })) + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : null)) ])); } if (widget.type == CollaborativeAreaType.workflow) { @@ -167,12 +172,16 @@ class SharedPageWidgetState extends State { 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 { + load: PermsService.getPerm(Perms.WORKFLOW_SHARE) ? (String change) async { await service.addWorkflow(context, CollaborativeAreaLocal.current ?? "", change); - }, - remove: (String change) async { + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : null, + remove: PermsService.getPerm(Perms.WORKFLOW_UNSHARE) ? (String change) async { await service.removeWorkflow(context, CollaborativeAreaLocal.current ?? "", change); - })) + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : null)) ])); } if (widget.type == CollaborativeAreaType.peer) { @@ -198,14 +207,19 @@ class SharedPageWidgetState extends State { 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 { + load: PermsService.getPerm(Perms.PEER_SHARE) ? (String change) async { await service.addPeer(context, CollaborativeAreaLocal.current ?? "", change); - }, - remove: (String change) async { + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : null, + remove: PermsService.getPerm(Perms.PEER_UNSHARE) ? (String change) async { await service.removePeer(context, CollaborativeAreaLocal.current ?? "", change); - })) + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : null)) ])); } + print(w); return Column( children: [ Container( height: 50, @@ -245,15 +259,12 @@ class SharedPageWidgetState extends State { filled: midColor, ) ], - create: PermsService.getPerm(Perms.COLLABORATIVE_AREA_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) async { if (e.data != null) { CollaborativeAreaLocal.current = e.data!.id; } - CollaborativeAreaLocal.init(context, true); - - HeaderConstants.setTitle("Collaborative Area <${CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? ""}>"); - HeaderConstants.setDescription(CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.description ?? ""); - Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); + await CollaborativeAreaLocal.init(context, true); + setState(() {}); }) : null, type: CollaborativeAreaType.collaborative_area, all: () async => CollaborativeAreaLocal.workspaces.values.map( @@ -284,7 +295,8 @@ class SharedPageWidgetState extends State { Container( height: getMainHeight(context) - 50, width: getMainWidth(context) -50, - color: widget.type == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer ? midColor : Colors.white, + color: widget.type == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer + || widget.type == CollaborativeAreaType.global ? midColor : Colors.white, child: SingleChildScrollView( child: w )) ] ) ] @@ -299,53 +311,265 @@ class WorkspaceSharedPageWidget extends StatefulWidget { } class WorkspaceSharedPageWidgetState extends State { - @override Widget build(BuildContext context) { - if (CollaborativeAreaLocal.current == null) { - return Container(); - } - var space = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]!; + List getCardWorkspaceItems(Map> data) { + List items = []; + for (var w1 in data.keys) { + for (var w in data[w1]!) { + List badges = []; + List bbadges = []; + badges.add(Container( margin: const EdgeInsets.only(left: 5), padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), + decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), + color: isData(w.topic) ? Colors.blue : isComputing(w.topic) ? Colors.green : + isCompute(w.topic) ? Colors.orange : isStorage(w.topic) ? redColor : Colors.grey ), + child:Text(w.topic, style: TextStyle( color: Colors.white, fontSize: 11) ))); + bbadges.add(Container( margin: const EdgeInsets.only(left: 5), + decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(4) ), + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Text(w1, style: TextStyle( color: Colors.white, fontSize: 11) ))); + items.add(ShallowItemFlowDataRowWidget( + color: Colors.grey.shade200, + item: w, badges: badges, bottomBadges: bbadges, + icon: Icons.shopping_cart, + contextWidth: 200 + )); + }} + return items; + } + + List getCardItems(List data) { List items = []; - List data = []; - if (widget.type == CollaborativeAreaType.global) { - } else if (widget.type == CollaborativeAreaType.workspace) { - data = space.workspaces; - } else if (widget.type == CollaborativeAreaType.workflow) { - data = space.workflows; - } else if (widget.type == CollaborativeAreaType.peer) { - data = space.peers; - } - var current = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]; for (var w in data) { - 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 == CollaborativeAreaType.workflow || widget.type == CollaborativeAreaType.peer) { - List badges = []; - if (widget.type == CollaborativeAreaType.peer && w.getID() == current?.creatorID) { - badges.add(Icons.star); - } - items.add(ShallowItemRowWidget( - item: w, badges: badges, - edit: widget.type == CollaborativeAreaType.workflow ? (String? change) { - if (change != null) { - WorkspaceLocal.changeWorkspaceByName(change.split("~")[1]); - } - Future.delayed(const Duration(seconds: 1), () => AppRouter.workflowIDItem.go(context, { "id": change ?? "" })); - } : null, - delete: (String? change) async { - if (change == null) { return; } - if (widget.type == CollaborativeAreaType.peer) { - await SharedService().removePeer(context, CollaborativeAreaLocal.current ?? "", change); - } else { - await SharedService().removePeer(context, CollaborativeAreaLocal.current ?? "", change); - } - }, - icon: widget.type == CollaborativeAreaType.workflow ? Icons.work_history_rounded : Icons.person, - contextWidth: 200) + List badges = []; + if (widget.type == CollaborativeAreaType.peer && w.getID( + ) == CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]?.rule?.creator) { + badges.add(Padding( padding: const EdgeInsets.only(left: 5), child: Icon(Icons.star, color: Colors.orange.shade300 ))); + } else if (widget.type == CollaborativeAreaType.workspace) { + badges.add(Container( margin: const EdgeInsets.only(left: 5), padding: EdgeInsets.all(5), color: Colors.grey.shade200, + child: Icon(Icons.star, color: Colors.orange.shade300,))); + } + items.add(ShallowItemRowWidget( + color: Colors.grey.shade200, + item: w, badges: badges, + delete: w is Peer && PermsService.getPerm(Perms.PEER_UNSHARE) ? (String? change) async { + await SharedService().removePeer(context, CollaborativeAreaLocal.current ?? "", change ?? ""); + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : (w is Workflow && PermsService.getPerm(Perms.WORKSPACE_UNSHARE)) ? (String? change) async { + await SharedService().removeWorkflow(context, CollaborativeAreaLocal.current ?? "", change ?? ""); + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + } : null, + icon: w is Workflow ? Icons.work_history_rounded : Icons.person, + contextWidth: 200 + )); + } + return items; + } + + @override Widget build(BuildContext context) { + var space = CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current ?? ""]; + if (widget.type == CollaborativeAreaType.global) { + if (space == null) { + return Container( + color: midColor, + height: getMainHeight(context) - 50, + width: getMainWidth(context) - 50, + alignment: Alignment.center, + padding: const EdgeInsets.all(50) ); } - } - if (items.isEmpty) { + final DateFormat formatter = DateFormat('dd-MM-yyyy'); + Peer? creator; + SharedService service = SharedService(); + try { creator = space.peers.firstWhere( (e) => (space.rule?.creator ?? "") == e.id); + } catch (e) { } + Map> datas = {}; + for (var w in space.workspaces) { + datas[w.getName()] = [ + ...w.computes, + ...w.datas, + ...w.processings, + ...w.storages, + ...w.workflows + ]; + } + return Padding( padding: EdgeInsets.all(30), + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + Text((CollaborativeAreaLocal.workspaces[CollaborativeAreaLocal.current]?.name ?? "").toUpperCase(), + style: TextStyle(color: Colors.grey, fontSize: 25, fontWeight: FontWeight.bold), textAlign: TextAlign.center, + softWrap: true, overflow: TextOverflow.ellipsis,), + ]), + Container( + width: getMainWidth(context) - 50, + margin: EdgeInsets.symmetric(vertical: 20), + color: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), + child: Text(space.description ?? "", + style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400, color: Colors.grey)) + ), // TODO + Text("COLLABORATIVE AREA ACCESS RULES", textAlign: TextAlign.start, + style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip), + Container( + width: getMainWidth(context) - 50, + margin: EdgeInsets.symmetric(vertical: 20), + color: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), + child: Column( + children: [ + Row(children: [ Text("Share mode : "), Text( space.rule?.shareMode ?? "closed", style: TextStyle( fontWeight: FontWeight.bold ) )],), + Row(children: [ Text("Created : "), Text( formatter.format(space.rule?.createdAt ?? DateTime.now()), style: TextStyle( fontWeight: FontWeight.bold )) ],), + creator != null ? Row(children: [ Text("Area master : "), Text( creator.getName(), style: TextStyle( fontWeight: FontWeight.bold ) ) ],) + : Container(), + Row(children: [ Text("User count : "), Text( "${space.peers.length}", style: TextStyle( fontWeight: FontWeight.bold )) ],), + Row(children: [ Text("Users profile : "), Text( space.rule?.exploitedBy ?? "any", style: TextStyle( fontWeight: FontWeight.bold ) ) ],), + ], + ) + ), + Row( children: [ + Text("COLLABORATIVE AREA PEERS", textAlign: TextAlign.start, + style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip), + PermsService.getPerm(Perms.PEER_SHARE) ? Container( + margin: EdgeInsets.only(left: 20), padding: EdgeInsets.only(left: 15), + decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.grey)) + ), child:ShallowDropdownInputWidget( + tooltipLoad: "add peer", + hint: "add peer", + iconLoad: Icons.add, + type: widget.type, + filled: midColor, + hintColor: Colors.grey, + color: Colors.black, + prefixIcon: Icon(Icons.person, color: Colors.grey), + all: () async { + List shals = []; + await PeerService().all(context).then((value) { + if (value.data != null) { + shals = value.data!.values.map((e) => Shallow(id: e["id"], name: e["name"])).where( (e) => !space.peers.map( (e) => e.id ).contains(e.id)).toList(); + } + setState(() {}); + }); + return shals; + }, + width: getMainWidth(context) / 3, + canLoad: (String? change) => !space.peers.map( (e) => e.id ).contains(change), + load: (String val) async { + await service.addPeer(context, CollaborativeAreaLocal.current ?? "", val); + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + }, + ) ) : Container()]), + Container( + width: getMainWidth(context) - 50, + margin: EdgeInsets.symmetric(vertical: 20), + color: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), + child: Wrap( alignment: WrapAlignment.center, children: getCardItems(space.peers)), + ), + Row( children: [ + Text("WORKSPACES / RESOURCES", textAlign: TextAlign.start, + style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip), + PermsService.getPerm(Perms.WORKSPACE_SHARE) ? Container( + margin: EdgeInsets.only(left: 20), padding: EdgeInsets.only(left: 15), + decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.grey)) + ), child: ShallowDropdownInputWidget( + tooltipLoad: "add workspace", + hint: "add workspace", + iconLoad: Icons.add, + type: widget.type, + filled: midColor, + hintColor: Colors.grey, + color: Colors.black, + prefixIcon: Icon(Icons.shopping_cart, color: Colors.grey), + all: () async => WorkspaceLocal.getWorkspacesShallow().where( (e) => !space.workspaces.map( (e) => e.id ).contains(e.id)).toList(), + width: getMainWidth(context) / 3, + canLoad: (String? change) => !space.workspaces.map( (e) => e.id ).contains(change), + load: (String val) async { + await service.addWorkspace(context, CollaborativeAreaLocal.current ?? "", val); + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + }, + )) : Container() ]), + Container( + width: getMainWidth(context) - 50, + margin: EdgeInsets.symmetric(vertical: 20), + color: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), + child: Wrap( alignment: WrapAlignment.center, children: getCardWorkspaceItems(datas)) + ), + Row( children: [ + Text("WORKFLOWS", textAlign: TextAlign.start, + style: TextStyle(color: darkColor, fontSize: 20, fontWeight: FontWeight.bold), overflow: TextOverflow.clip), + PermsService.getPerm(Perms.WORKFLOW_SHARE) ? Container( + margin: EdgeInsets.only(left: 20), padding: EdgeInsets.only(left: 15), + decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.grey)) + ), child:ShallowDropdownInputWidget( + tooltipLoad: "add workflow", + hint: "add workflow", + iconLoad: Icons.add, + type: widget.type, + filled: midColor, + hintColor: Colors.grey, + color: Colors.black, + prefixIcon: Icon(Icons.rebase_edit, color: Colors.grey), + all: () async { + List shals = []; + await WorflowService().all(context).then((value) { + if (value.data != null) { + shals = value.data!.values.map((e) => Shallow(id: e["id"], name: e["name"])).where( (e) => !space.workflows.map( (e) => e.id ).contains(e.id)).toList(); + } + }); + return shals; + }, + width: getMainWidth(context) / 3, + canLoad: (String? change) => !space.workflows.map( (e) => e.id ).contains(change), + load: (String val) async { + await service.addWorkflow(context, CollaborativeAreaLocal.current ?? "", val); + await CollaborativeAreaLocal.init(context, false); + setState(() {}); + }, + )) : Container()]), + Container( + width: getMainWidth(context) - 50, + margin: EdgeInsets.symmetric(vertical: 20), + color: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), + child: Wrap( alignment: WrapAlignment.center, children: getCardItems(space.workflows)) + ), + ],) + ); + } + if (CollaborativeAreaLocal.current == null) { + return Container( + color: midColor, + height: getMainHeight(context) - 50, + width: getMainWidth(context) - 50, + alignment: Alignment.center, + padding: const EdgeInsets.all(50) + ); + } + List items = []; + List data = []; + if (widget.type == CollaborativeAreaType.workspace) { + data = space?.workspaces ?? []; + } else if (widget.type == CollaborativeAreaType.workflow) { + data = space?.workflows ?? []; + } else if (widget.type == CollaborativeAreaType.peer) { + data = space?.peers ?? []; + } + if (widget.type == CollaborativeAreaType.workspace) { + for (var w in data) { + 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 { + items = getCardItems(data); + } + if (items.isEmpty) { return Container( color: midColor, height: getMainHeight(context) - 50, @@ -377,18 +601,18 @@ class WorkspaceSharedItemPageWidgetState extends State setState(() { widget.open = !widget.open; }))) diff --git a/lib/pages/workflow.dart b/lib/pages/workflow.dart index 0b6bed5..ef7875d 100644 --- a/lib/pages/workflow.dart +++ b/lib/pages/workflow.dart @@ -23,7 +23,6 @@ import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; Dashboard dash = Dashboard(name: ""); class WorkflowFactory 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) { diff --git a/lib/widgets/dialog/login.dart b/lib/widgets/dialog/login.dart index 11dd4c1..53e2c29 100644 --- a/lib/widgets/dialog/login.dart +++ b/lib/widgets/dialog/login.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:go_router/go_router.dart'; import 'package:oc_front/core/services/auth.service.dart'; @@ -14,9 +15,34 @@ class LoginWidgetState extends State { String? error; bool loading = false; - + FocusNode focusNode = FocusNode(); @override Widget build(BuildContext context) { - return Padding(padding: const EdgeInsets.all(50), child: Column(mainAxisSize: MainAxisSize.min, children: [ + return KeyboardListener(focusNode: focusNode, + onKeyEvent: (value) { + if (value is KeyDownEvent && value.logicalKey == LogicalKeyboardKey.enter) { + if (usernameCtrl.text == "" || passwordCtrl.text == "") { return; } + error = null; + setState(() { + loading = true; + }); + 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(); + } + } + }, + child: 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, @@ -100,6 +126,6 @@ class LoginWidgetState extends State { fontSize: 15) ))))), ]) ]), - ],)); + ],))); } } \ No newline at end of file diff --git a/lib/widgets/forms/scheduler_forms.dart b/lib/widgets/forms/scheduler_forms.dart index 411dcac..d80350c 100644 --- a/lib/widgets/forms/scheduler_forms.dart +++ b/lib/widgets/forms/scheduler_forms.dart @@ -12,6 +12,7 @@ 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'; +import 'package:oc_front/widgets/dialog/confirm_box.dart'; import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; class SchedulerFormsWidget extends StatefulWidget { @@ -113,12 +114,19 @@ class SchedulerFormsWidgetState extends State { 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 = ""; - dash.isOpened = false; - dash.clear(); - dash.chartKey.currentState?.widget.flowChart.setState(() { }); + showDialog(context: context, builder: (context) { + return ConfirmBoxWidget( + purpose: "Are you sure you want to delete this workflow?", + validate: () async { + await WorflowService().delete(context, widget.item.id ?? "", {}).then((value) { + dash.id = null; + dash.name = ""; + dash.isOpened = false; + dash.clear(); + dash.chartKey.currentState?.widget.flowChart.setState(() { }); + }); + }, + ); }); } : null, ); @@ -464,9 +472,9 @@ class SchedulerFormsWidgetState extends State { ), widget.item.info["shared"] != null && (widget.item.info["shared"] as List).isNotEmpty ? Column( children: [ Container( - height: 20, + height: 30, width: 200, - decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.black))), + decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.grey))), ), Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10), child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, diff --git a/lib/widgets/items/shallow_item_row.dart b/lib/widgets/items/shallow_item_row.dart index 97fc7c2..5b9d20e 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:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:oc_front/main.dart'; import 'package:oc_front/models/response.dart'; @@ -9,15 +10,16 @@ const List> _empty = []; class ShallowItemRowWidget extends StatefulWidget { bool readOnly = false; double contextWidth = 0; + Color? color; ShallowData item; IconData? icon; bool low = false; bool show = false; - List badges = []; + List badges = []; void Function(String?)? delete; void Function(String?)? edit; List> keys = []; - ShallowItemRowWidget ({ super.key, this.low = false, this.icon, this.delete, this.edit, this.badges = const [], + ShallowItemRowWidget ({ super.key, this.low = false, this.icon, this.delete, this.edit, this.color, this.badges = const [], required this.contextWidth, this.readOnly = false, required this.item, this.keys = _empty }); @override ShallowItemRowWidgetState createState() => ShallowItemRowWidgetState(); } @@ -32,8 +34,80 @@ class ShallowItemRowWidgetState extends State { }), child: Container( height: widget.contextWidth, width: widget.contextWidth, - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: Colors.white, + padding: const EdgeInsets.all(10), + margin: const EdgeInsets.all(10), + decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: widget.color ?? Colors.white, + boxShadow: const [BoxShadow(color: Colors.grey, spreadRadius: 1, blurRadius: 1, offset: Offset(0, 1))]), + child: Stack( children: [ + widget.show ? Positioned( left: 0, top: 0, + child: Row( children: [ + Padding( padding: const EdgeInsets.only(right: 5), + child: widget.edit == null ? Container() : InkWell( mouseCursor: SystemMouseCursors.click, + onTap: () => widget.edit!(widget.item.getID() + "~" + widget.item.getName()), child: const Icon(Icons.edit, color: Colors.grey,))), + Padding( padding: const EdgeInsets.only(right: 5), + child: widget.delete == null ? Container() : InkWell( mouseCursor: SystemMouseCursors.click, + onTap: () => widget.delete!(widget.item.getID()), child: const Icon(Icons.delete, color: Colors.grey,))), + ] )) : Container(), + Positioned( right: 0, top: 0, child: Row( children: widget.badges )), + Column( children: [ + widget.low || widget.icon == null ? Container( padding: const EdgeInsets.only(left: 10),) : Container( padding: const EdgeInsets.all(10), + 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 != getMainWidth(context) ? + const EdgeInsets.symmetric(horizontal: 10) : const EdgeInsets.symmetric(horizontal: 20), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ + Row( children: [ + Expanded( child: Center( child: Text(widget.item.getName().toUpperCase(), + style: const TextStyle(fontSize: 15, + overflow: TextOverflow.ellipsis, + fontWeight: FontWeight.w600, color: Colors.grey)), + )) + ]), + ],) + ) + ), + ]) + ])))); + return widget.readOnly || widget.low ? w : InkWell( mouseCursor: SystemMouseCursors.click, + onTap: () { }, + child: w ); + } +} + +class ShallowItemFlowDataRowWidget extends StatefulWidget { + bool readOnly = false; + double contextWidth = 0; + Color? color; + FlowData item; + IconData? icon; + bool low = false; + bool show = false; + List badges = []; + List bottomBadges = []; + void Function(String?)? delete; + void Function(String?)? edit; + List> keys = []; + ShallowItemFlowDataRowWidget ({ super.key, this.low = false, this.icon, this.delete, this.bottomBadges = const [], + this.edit, this.color, this.badges = const [], + required this.contextWidth, this.readOnly = false, required this.item, this.keys = _empty }); + @override ShallowItemFlowDataRowWidgetState createState() => ShallowItemFlowDataRowWidgetState(); +} +class ShallowItemFlowDataRowWidgetState extends State { + @override Widget build(BuildContext context) { + Widget w = Tooltip( message: widget.item.getName(), child: MouseRegion( + onHover: (e) => setState(() { + widget.show = true; + }), + onExit: (e) => setState(() { + widget.show = false; + }), + child: Container( + height: widget.contextWidth, width: widget.contextWidth, + padding: const EdgeInsets.all(10), + margin: const EdgeInsets.all(10), + decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: widget.color ?? Colors.white, boxShadow: const [BoxShadow(color: Colors.grey, spreadRadius: 1, blurRadius: 1, offset: Offset(0, 1))]), child: Stack( children: [ widget.show ? Positioned( left: 0, top: 0, @@ -46,7 +120,9 @@ class ShallowItemRowWidgetState extends State { onTap: () => widget.delete!(widget.item.getID()), child: const Icon(Icons.delete, color: Colors.grey,))), ] )) : Container(), Positioned( right: 0, top: 0, - child: Row( children: widget.badges.map( (e) => Padding( padding: const EdgeInsets.only(left: 5), child: Icon(e, color: Colors.orange.shade300,))).toList() )), + child: Row( children: widget.badges )), + Positioned( left: 0, bottom: 0, + child: Row( children: widget.bottomBadges )), Column( children: [ widget.low || widget.icon == null ? Container( padding: const EdgeInsets.only(left: 10),) : Container( padding: const EdgeInsets.all(10), constraints: BoxConstraints(maxWidth: widget.contextWidth, minWidth: widget.contextWidth), diff --git a/lib/widgets/sheduler_items/schedule.dart b/lib/widgets/sheduler_items/schedule.dart index d55cb1a..01384d3 100644 --- a/lib/widgets/sheduler_items/schedule.dart +++ b/lib/widgets/sheduler_items/schedule.dart @@ -29,7 +29,7 @@ class ScheduleWidgetState extends State { String search = ""; String? level; List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "MISSED"]; DateTime getFocusedDay() { if (selected != null) { return DateTime.parse(selected!); } diff --git a/lib/widgets/sheduler_items/scheduler_calendar.dart b/lib/widgets/sheduler_items/scheduler_calendar.dart index 17e75f0..79865c3 100644 --- a/lib/widgets/sheduler_items/scheduler_calendar.dart +++ b/lib/widgets/sheduler_items/scheduler_calendar.dart @@ -25,7 +25,7 @@ class SchedulerCalendarWidget extends StatefulWidget { } class SchedulerCalendarWidgetState extends State { List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "MISSED"]; bool isEvent(Map> data, DateTime day) { if (data[day.toIso8601String()] == null || data[day.toIso8601String()]!.isEmpty) { return false; } return true; diff --git a/lib/widgets/sheduler_items/scheduler_item.dart b/lib/widgets/sheduler_items/scheduler_item.dart index 4d32780..4052515 100644 --- a/lib/widgets/sheduler_items/scheduler_item.dart +++ b/lib/widgets/sheduler_items/scheduler_item.dart @@ -19,7 +19,7 @@ class SchedulerItemWidget extends StatefulWidget { } class SchedulerItemWidgetState extends State { List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "MISSED"]; @override Widget build(BuildContext context) { List children = []; diff --git a/local_run.sh b/local_run.sh index 2fb4d06..216672d 100755 --- a/local_run.sh +++ b/local_run.sh @@ -10,4 +10,6 @@ COLLABORATIVE_AREA_HOST='http://localhost:8091/oc' AUTH_HOST='http://localhost:8094/oc' DATACENTER_HOST='http://localhost:8092/oc' -flutter run -d linux --dart-define=DATACENTER_HOST=$DATACENTER_HOST --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 +AUTH_MODE=true + +flutter run -d linux --dart-define=AUTH_MODE=$AUTH_MODE --dart-define=DATACENTER_HOST=$DATACENTER_HOST --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