From b16104bb6adccf2f91c376c270f8d20105fbdf16 Mon Sep 17 00:00:00 2001 From: mr Date: Fri, 6 Mar 2026 10:26:00 +0100 Subject: [PATCH] oauth2 state of mind --- Dockerfile | 52 ++- assets/images/workflow_event.svg | 6 + docker-compose.yml | 1 - lib/core/conf/conf_reader.dart | 6 +- lib/core/services/auth.service.dart | 5 +- lib/core/services/oauth2.service.dart | 213 ++++++++++++ lib/core/services/perms_service.dart | 1 + lib/core/services/redirect_stub.dart | 1 + lib/core/services/redirect_web.dart | 4 + lib/main.dart | 42 ++- lib/models/resources/resources.dart | 3 + lib/models/resources/workflow_event.dart | 77 +++++ lib/models/workflow.dart | 29 +- lib/pages/catalog_item.dart | 2 +- lib/pages/workflow.dart | 38 ++- lib/widgets/dialog/login.dart | 17 +- lib/widgets/forms/workflow_event_forms.dart | 86 +++++ .../.dart_tool/package_config.json | 16 +- .../.dart_tool/package_config_subset | 16 +- library/flutter_flow_chart/pubspec.lock | 10 +- library/flutter_flow_chart/pubspec.yaml | 1 - linux/flutter/generated_plugin_registrant.cc | 16 +- linux/flutter/generated_plugins.cmake | 4 +- macos/Flutter/GeneratedPluginRegistrant.swift | 12 +- pubspec.lock | 302 ++++++------------ pubspec.yaml | 19 +- .../flutter/generated_plugin_registrant.cc | 12 +- windows/flutter/generated_plugins.cmake | 4 +- 28 files changed, 628 insertions(+), 367 deletions(-) create mode 100644 assets/images/workflow_event.svg create mode 100644 lib/core/services/oauth2.service.dart create mode 100644 lib/core/services/redirect_stub.dart create mode 100644 lib/core/services/redirect_web.dart create mode 100644 lib/models/resources/workflow_event.dart create mode 100644 lib/widgets/forms/workflow_event_forms.dart diff --git a/Dockerfile b/Dockerfile index 8c683a6..a9df6e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,52 +1,42 @@ -# Environemnt to install flutter and build web -FROM debian:latest AS build-env +FROM debian:bookworm-slim AS build-env -ARG HOST=${HOST:-"http://localhost:8000"} +ARG HOST="http://localhost:8000" ARG AUTH_MODE=true -# install all needed stuff -RUN apt-get update -RUN apt-get install -y curl git unzip +RUN apt-get update && apt-get install -y \ + curl \ + git \ + unzip \ + xz-utils \ + zip \ + libglu1-mesa \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* -# define variables -ARG FLUTTER_SDK=/usr/local/flutter -ARG FLUTTER_VERSION=3.19.6 -ARG APP=/app/ +RUN update-ca-certificates + +ARG FLUTTER_SDK=/usr/local/flutter +ARG FLUTTER_VERSION=3.24.3 +ARG APP=/app -#clone flutter RUN git clone https://github.com/flutter/flutter.git $FLUTTER_SDK -# change dir to current flutter folder and make a checkout to the specific version -RUN cd $FLUTTER_SDK && git fetch && git checkout $FLUTTER_VERSION +RUN cd $FLUTTER_SDK && git checkout $FLUTTER_VERSION -# setup the flutter path as an enviromental variable ENV PATH="$FLUTTER_SDK/bin:$FLUTTER_SDK/bin/cache/dart-sdk/bin:${PATH}" -# Start to run Flutter commands -# doctor to see if all was installes ok +RUN flutter config --enable-web RUN flutter doctor -v -# create folder to copy source code -RUN mkdir $APP -# copy source code to folder -COPY . $APP -# stup new folder as the working directory WORKDIR $APP +COPY . . -# Run build: 1 - clean, 2 - pub get, 3 - build web RUN flutter clean RUN flutter pub get -RUN flutter build web \ +RUN flutter build web \ --dart-define=AUTH_MODE=$AUTH_MODE \ --dart-define=HOST=$HOST -# once heare the app will be compiled and ready to deploy - -# use nginx to deploy FROM nginx:1.25.2-alpine - -# copy the info of the builded web app to nginx COPY --from=build-env /app/build/web /usr/share/nginx/html - -# Expose and run nginx EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file +CMD ["nginx", "-g", "daemon off;"] diff --git a/assets/images/workflow_event.svg b/assets/images/workflow_event.svg new file mode 100644 index 0000000..18145dc --- /dev/null +++ b/assets/images/workflow_event.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/docker-compose.yml b/docker-compose.yml index 87ab011..ce25084 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,6 @@ services: - "traefik.http.services.front.loadbalancer.server.port=80" - "traefik.http.middlewares.front-stripprefix.stripprefix.prefixes=/" - "traefik.http.routers.front.middlewares=front-stripprefix" - - "traefik.http.middlewares.front.forwardauth.address=http://oc-auth:8080/oc/forward" networks: oc: external: true \ No newline at end of file diff --git a/lib/core/conf/conf_reader.dart b/lib/core/conf/conf_reader.dart index 1e473a8..b3619c7 100644 --- a/lib/core/conf/conf_reader.dart +++ b/lib/core/conf/conf_reader.dart @@ -3,7 +3,7 @@ import 'package:flutter/services.dart'; class AppConfig { static final AppConfig _instance = AppConfig._internal(); - Map _config = {}; + final Map _config = {}; AppConfig._internal(); @@ -11,7 +11,9 @@ class AppConfig { Future loadConfig() async { final response = await rootBundle.loadString('assets/config/front.json'); - _config = Map.from(json.decode(response)); + for (var v in Map.from(json.decode(response)).entries) { + _config[v.key] = v.value; + } } String get(String key, {String defaultValue = ''}) { diff --git a/lib/core/services/auth.service.dart b/lib/core/services/auth.service.dart index 7139afd..3e02dce 100644 --- a/lib/core/services/auth.service.dart +++ b/lib/core/services/auth.service.dart @@ -48,10 +48,11 @@ class AuthService { return localStorage.getItem('username') ?? "unknown"; } - static Future login(String username, String password) async { + static Future login(String username, String password, String? challenge) async { var token = await service!.post("/login?client_id=$_clientID", { "username": username, - "password": password + "password": password, + "challenge": challenge }, null); if (token.code == 200 && token.data != null) { localStorage.setItem('accessToken', token.data?.value['access_token']); diff --git a/lib/core/services/oauth2.service.dart b/lib/core/services/oauth2.service.dart new file mode 100644 index 0000000..4d94108 --- /dev/null +++ b/lib/core/services/oauth2.service.dart @@ -0,0 +1,213 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:jwt_decoder/jwt_decoder.dart'; +import 'package:localstorage/localstorage.dart'; +import 'package:oc_front/core/conf/conf_reader.dart'; +import 'package:oc_front/core/services/redirect_stub.dart' + if (dart.library.html) 'package:oc_front/core/services/redirect_web.dart'; + +class OAuthConfig { + static final clientId = AppConfig().get('CLIENT_ID', defaultValue: 'test-client'); + static final host = AppConfig().get('HOST', defaultValue: 'http://localhost:8000'); + static final redirectUri = kIsWeb ? host : 'ocforge://callback'; + static final issuer = '$host/hydra'; + + static final authorizationEndpoint = '$issuer/auth'; + static final tokenEndpoint = '$issuer/token'; + static final endSessionEndpoint = '$issuer/sessions/logout'; + + static final scopes = ['openid', 'profile', 'email', 'role']; +} + +class TokenStorage { + static const _accessToken = 'access_token'; + static const _refreshToken = 'refresh_token'; + static const _idToken = 'id_token'; + + final _storage = const FlutterSecureStorage(); + + Future save({ + required String accessToken, + required String refreshToken, + String? idToken, + }) async { + await _storage.write(key: _accessToken, value: accessToken); + await _storage.write(key: _refreshToken, value: refreshToken); + if (idToken != null) { + await _storage.write(key: _idToken, value: idToken); + } + } + + Future getAccessToken() => _storage.read(key: _accessToken); + Future getRefreshToken() => _storage.read(key: _refreshToken); + Future getIdToken() => _storage.read(key: _idToken); + + Future clear() async => _storage.deleteAll(); +} + +class OAuth2Service { + static final OAuth2Service _instance = OAuth2Service._internal(); + factory OAuth2Service() => _instance; + OAuth2Service._internal(); + + final TokenStorage _storage = TokenStorage(); + final _dio = Dio(BaseOptions( + headers: {'Content-Type': 'application/json; charset=UTF-8'}, + validateStatus: (status) => status != null && status < 500, + )); + + /// Initiates the Hydra headless auth flow. + /// + /// - If already authenticated, returns null. + /// - If [login_challenge] is present in the URL query params (web), returns it. + /// - Otherwise redirects the browser to Hydra's authorization endpoint, + /// which will redirect back to this app with ?login_challenge=<...>. + /// Returns null in this case (page is reloading). + Future initFlow() async { + if (await isAuthenticated()) return null; + + if (kIsWeb) { + final challenge = Uri.base.queryParameters['login_challenge']; + if (challenge != null) return challenge; + + // No token and no challenge: kick off the OAuth2 authorization code flow. + // Hydra will redirect back to redirectUri with ?login_challenge=<...>. + final authUrl = Uri.parse(OAuthConfig.authorizationEndpoint).replace( + queryParameters: { + 'client_id': OAuthConfig.clientId, + 'response_type': 'code', + 'scope': OAuthConfig.scopes.join(' '), + 'redirect_uri': OAuthConfig.redirectUri, + }, + ).toString(); + browserRedirect(authUrl); + } + return null; + } + + /// Headless login: POSTs credentials + challenge to the backend. + /// + /// The backend accepts the login with Hydra and returns tokens directly. + /// Tokens are stored in [FlutterSecureStorage] and synced to [localStorage] + /// so that the existing API service keeps sending the Bearer header. + Future login(String username, String password, String challenge) async { + final response = await _dio.post( + '${OAuthConfig.host}/auth/login', + queryParameters: {'client_id': OAuthConfig.clientId}, + data: { + 'username': username, + 'password': password, + 'challenge': challenge, + }, + ); + + if (response.statusCode != 200 || response.data == null) { + throw Exception('Login failed: ${response.statusMessage}'); + } + + final data = Map.from(response.data as Map); + final accessToken = data['access_token'] as String? ?? ''; + final refreshToken = data['refresh_token'] as String? ?? ''; + final idToken = data['id_token'] as String?; + final expiresIn = data['expires_in'] as int? ?? 3600; + + await _storage.save( + accessToken: accessToken, + refreshToken: refreshToken, + idToken: idToken, + ); + + // Sync to localStorage so api_service.dart keeps sending the Bearer header. + localStorage.setItem('accessToken', accessToken); + localStorage.setItem('tokenType', data['token_type'] as String? ?? 'Bearer'); + localStorage.setItem('username', username); + localStorage.setItem( + 'expiresIn', + DateTime.now().add(Duration(seconds: expiresIn)).toIso8601String(), + ); + } + + /// Returns a valid access token, auto-refreshing via the Hydra token + /// endpoint if the stored one is expired. + Future getValidAccessToken() async { + final accessToken = await _storage.getAccessToken(); + if (accessToken == null || accessToken.isEmpty) return null; + + try { + if (!JwtDecoder.isExpired(accessToken)) return accessToken; + } catch (_) { + return accessToken; // not a JWT — trust it as-is + } + + final refreshToken = await _storage.getRefreshToken(); + if (refreshToken == null || refreshToken.isEmpty) { + await logout(); + return null; + } + return _refresh(refreshToken); + } + + /// Exchanges a refresh token for a new access token via the standard + /// OAuth2 token endpoint (grant_type=refresh_token). + Future _refresh(String refreshToken) async { + try { + final response = await _dio.post( + OAuthConfig.tokenEndpoint, + data: { + 'grant_type': 'refresh_token', + 'client_id': OAuthConfig.clientId, + 'refresh_token': refreshToken, + 'scope': OAuthConfig.scopes.join(' '), + }, + options: Options(contentType: 'application/x-www-form-urlencoded'), + ); + + if (response.statusCode != 200 || response.data == null) { + await logout(); + return null; + } + + final data = Map.from(response.data as Map); + final newAccess = data['access_token'] as String? ?? ''; + final newRefresh = data['refresh_token'] as String? ?? refreshToken; + final idToken = data['id_token'] as String?; + + await _storage.save( + accessToken: newAccess, + refreshToken: newRefresh, + idToken: idToken, + ); + localStorage.setItem('accessToken', newAccess); + return newAccess; + } catch (_) { + await logout(); + return null; + } + } + + /// Clears stored tokens and redirects to Hydra's end-session endpoint (web). + Future logout() async { + final idToken = await _storage.getIdToken(); + await _storage.clear(); + + localStorage.setItem('accessToken', ''); + localStorage.setItem('username', ''); + localStorage.setItem('expiresIn', ''); + + if (kIsWeb && idToken != null) { + final logoutUrl = Uri.parse(OAuthConfig.endSessionEndpoint).replace( + queryParameters: { + 'id_token_hint': idToken, + 'post_logout_redirect_uri': OAuthConfig.redirectUri, + }, + ).toString(); + browserRedirect(logoutUrl); + } + } + + Future isAuthenticated() async { + final token = await getValidAccessToken(); + return token != null; + } +} diff --git a/lib/core/services/perms_service.dart b/lib/core/services/perms_service.dart index 3be9fc8..9cc5c60 100644 --- a/lib/core/services/perms_service.dart +++ b/lib/core/services/perms_service.dart @@ -88,6 +88,7 @@ class PermsService { }); } static bool getPerm(Perms perm) { + return true; return _perms[perm] ?? false; } diff --git a/lib/core/services/redirect_stub.dart b/lib/core/services/redirect_stub.dart new file mode 100644 index 0000000..ffdbb8c --- /dev/null +++ b/lib/core/services/redirect_stub.dart @@ -0,0 +1 @@ +void browserRedirect(String url) {} diff --git a/lib/core/services/redirect_web.dart b/lib/core/services/redirect_web.dart new file mode 100644 index 0000000..737efae --- /dev/null +++ b/lib/core/services/redirect_web.dart @@ -0,0 +1,4 @@ +// ignore: avoid_web_libraries_in_flutter +import 'dart:html' as html; + +void browserRedirect(String url) => html.window.location.href = url; diff --git a/lib/main.dart b/lib/main.dart index b13fbc3..4694e49 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,19 +1,20 @@ import 'dart:async'; -import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:localstorage/localstorage.dart'; +import 'package:oc_front/core/services/router.dart'; +import 'package:oc_front/widgets/dialog/login.dart'; +import 'package:oc_front/core/conf/conf_reader.dart'; +import 'package:oc_front/core/sections/left_menu.dart'; +import 'package:oc_front/core/sections/end_drawer.dart'; +import 'package:oc_front/core/sections/header/menu.dart'; +import 'package:oc_front/core/services/auth.service.dart'; +import 'package:oc_front/core/services/oauth2.service.dart'; +import 'package:oc_front/core/services/enum_service.dart'; import 'package:oc_front/core/models/workspace_local.dart'; import 'package:oc_front/core/sections/header/header.dart'; -import 'package:oc_front/core/sections/header/menu.dart'; -import 'package:oc_front/core/sections/left_menu.dart'; -import 'package:oc_front/core/services/auth.service.dart'; -import 'package:oc_front/core/services/enum_service.dart'; -import 'package:oc_front/core/services/router.dart'; -import 'package:oc_front/core/sections/end_drawer.dart'; -import 'package:oc_front/widgets/dialog/login.dart'; + void main() async { WidgetsFlutterBinding.ensureInitialized(); // Run `LinuxWebViewPlugin.initialize()` first before creating a WebView. @@ -30,6 +31,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // Future.delayed(Duration(seconds: 2), () => AppRouter.verifyRoute(context)); + AppConfig().loadConfig(); AuthService.init(); EnumService.init(); SearchConstants.clear(); @@ -56,11 +58,11 @@ class MainPage extends StatefulWidget { State createState() => MainPageState(); } -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); +var darkColor = const Color.fromRGBO(26, 83, 92, 1); +var lightColor = const Color.fromRGBO(78, 205, 196, 1); +var darkMidColor = const Color.fromRGBO(44, 83, 100, 1); +var midColor = Colors.grey.shade300; +var redColor = const Color.fromRGBO(255, 107, 107, 1); double getWidth(BuildContext context) { return MediaQuery.of(context).size.width <= 800 @@ -99,10 +101,17 @@ 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.i + scaffoldKey = GlobalKey(); if (!AuthService.isConnected() && !loginIsSet) { - Future.delayed(const Duration(milliseconds: 500), () { + Future.delayed(const Duration(milliseconds: 500), () async { loginIsSet = true; + // initFlow() returns the login_challenge from the URL if present, + // or redirects the browser to Hydra's auth endpoint (web) and + // returns null while the page reloads with ?login_challenge=<...>. + final challenge = await OAuth2Service().initFlow(); + if (challenge == null) return; + // ignore: use_build_context_synchronously showDialog( barrierDismissible: false, // ignore: use_build_context_synchronously @@ -112,7 +121,7 @@ class MainPageState extends State { backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), - title: LoginWidget()); + title: LoginWidget(loginChallenge: challenge)); }); }); } @@ -138,7 +147,6 @@ class MainPageState extends State { onKeyEvent: (event) async { if( (event is KeyDownEvent) && event.logicalKey == LogicalKeyboardKey.enter) { AppRouter.currentRoute.factory.search(context, false); - node.requestFocus(); } }, child: Column( diff --git a/lib/models/resources/resources.dart b/lib/models/resources/resources.dart index 330f72c..b0bed5d 100644 --- a/lib/models/resources/resources.dart +++ b/lib/models/resources/resources.dart @@ -7,6 +7,7 @@ import 'package:oc_front/models/resources/data.dart'; import 'package:oc_front/models/resources/processing.dart'; import 'package:oc_front/models/resources/storage.dart'; import 'package:oc_front/models/resources/workflow.dart'; +import 'package:oc_front/models/resources/workflow_event.dart'; class Resource implements SerializerDeserializer { List datas = []; @@ -503,6 +504,7 @@ Type? getTopicType(String topic) { else if (topic == "compute") { return ComputeItem; } else if (topic == "storage") { return StorageItem; } else if (topic == "workflow") { return WorkflowItem; } + else if (topic == "event") { return WorkflowEventItem; } else { return null; } } @@ -513,6 +515,7 @@ String getTopic(Type type) { if (type == ComputeItem) { return "compute"; } if (type == StorageItem) { return "storage"; } if (type == WorkflowItem) { return "workflow"; } + if (type == WorkflowEventItem) { return "event"; } return ""; } diff --git a/lib/models/resources/workflow_event.dart b/lib/models/resources/workflow_event.dart new file mode 100644 index 0000000..04fe04c --- /dev/null +++ b/lib/models/resources/workflow_event.dart @@ -0,0 +1,77 @@ + +import 'package:oc_front/models/resources/resources.dart'; + +class WorkflowEventItem extends AbstractItem { + // workflow_execution_id: id of the workflow execution this event targets + String? workflowExecutionId; + + WorkflowEventItem({ + this.workflowExecutionId, + }) : super(); + + @override String get topic => "event"; + + @override WorkflowEventItem deserialize(dynamic data) { + try { data = data as Map; + } catch (e) { return WorkflowEventItem(); } + var w = WorkflowEventItem( + workflowExecutionId: data.containsKey("workflow_execution_id") && data["workflow_execution_id"] != null + ? data["workflow_execution_id"] : null, + ); + w.mapFromJSON(data, WorkflowEventInstance()); + return w; + } + + @override Map infos() { + return { + if (workflowExecutionId != null) "workflow_execution_id": workflowExecutionId, + }; + } + + @override Map serialize() { + var obj = { + "workflow_execution_id": workflowExecutionId, + }; + obj.addAll(toJSON()); + return obj; + } +} + +class WorkflowEventInstance extends AbstractInstance { + WorkflowEventInstance() : super(); + + @override WorkflowEventInstance deserialize(dynamic json) { + try { json = json as Map; + } catch (e) { return WorkflowEventInstance(); } + var w = WorkflowEventInstance(); + w.mapFromJSON(json, WorkflowEventPartnership()); + return w; + } + + @override Map infos() => {}; + + @override Map serialize() => toJSON(); +} + +class WorkflowEventPartnership extends AbstractPartnerShip { + WorkflowEventPartnership() : super(); + + @override WorkflowEventPartnership deserialize(dynamic json) { + try { json = json as Map; + } catch (e) { return WorkflowEventPartnership(); } + var w = WorkflowEventPartnership(); + w.mapFromJSON(json, WorkflowEventPricing()); + return w; + } + + @override Map serialize() => toJSON(); +} + +class WorkflowEventPricing extends AbstractPricing { + @override WorkflowEventPricing deserialize(dynamic json) { + var w = WorkflowEventPricing(); + w.mapFromJSON(json); + return w; + } + @override Map serialize() => toJSON(); +} diff --git a/lib/models/workflow.dart b/lib/models/workflow.dart index fb53c9e..ee71025 100644 --- a/lib/models/workflow.dart +++ b/lib/models/workflow.dart @@ -9,6 +9,7 @@ import 'package:oc_front/models/resources/processing.dart'; import 'package:oc_front/models/resources/resources.dart'; import 'package:oc_front/models/resources/storage.dart'; import 'package:oc_front/models/resources/workflow.dart'; +import 'package:oc_front/models/resources/workflow_event.dart'; import 'package:oc_front/models/response.dart'; import 'package:oc_front/widgets/forms/sub_keys_forms.dart'; @@ -108,6 +109,7 @@ class Workflow extends SerializerDeserializer implements ShallowData List storage; List processing; List workflows; + List events; Graph? graph; List shared; @@ -119,6 +121,7 @@ class Workflow extends SerializerDeserializer implements ShallowData this.storage = const [], this.processing = const [], this.workflows = const [], + this.events = const [], this.graph, this.shared = const [], }); @@ -138,6 +141,7 @@ class Workflow extends SerializerDeserializer implements ShallowData compute: json.containsKey("computes") ? json["computes"] : [], data: json.containsKey("datas") ? json["datas"] : [], storage: json.containsKey("storages") ? json["storages"] : [], + events: json.containsKey("events") ? json["events"] : [], shared: json.containsKey("shared") ? json["shared"] : [], graph: json.containsKey("graph") ? Graph().deserialize(json["graph"]) : null, ); @@ -151,6 +155,7 @@ class Workflow extends SerializerDeserializer implements ShallowData "computes" : compute, "workflows": workflows, "processings": processing, + "events": events, }; if (graph != null) { obj["graph"] = graph!.serialize(); @@ -690,6 +695,7 @@ class GraphItem extends SerializerDeserializer { StorageItem? storage; ComputeItem? compute; WorkflowItem? workflow; + WorkflowEventItem? event; GraphItem({ this.id, @@ -701,6 +707,7 @@ class GraphItem extends SerializerDeserializer { this.storage, this.compute, this.workflow, + this.event, }); AbstractItem? getElement() { @@ -709,6 +716,7 @@ class GraphItem extends SerializerDeserializer { if (storage != null) { return storage!; } if (compute != null) { return compute!; } if (workflow != null) { return workflow!; } + if (event != null) { return event!; } return null; } @@ -720,17 +728,19 @@ class GraphItem extends SerializerDeserializer { height = j["height"]; if (j["element"] != null) { - if (j["element"]["type"] == "data") { data = DataItem().deserialize(j["element"]); + if (j["element"]["type"] == "data") { data = DataItem().deserialize(j["element"]); } else if (j["element"]["type"] == "processing") { processing = ProcessingItem().deserialize(j["element"]); - } else if (j["element"]["type"] == "compute") { compute = ComputeItem().deserialize(j["element"]); - } else if (j["element"]["type"] == "storage") { storage = StorageItem().deserialize(j["element"]); - } else if (j["element"]["type"] == "workflow") { workflow = WorkflowItem().deserialize(j["element"]); + } else if (j["element"]["type"] == "compute") { compute = ComputeItem().deserialize(j["element"]); + } else if (j["element"]["type"] == "storage") { storage = StorageItem().deserialize(j["element"]); + } else if (j["element"]["type"] == "workflow") { workflow = WorkflowItem().deserialize(j["element"]); + } else if (j["element"]["type"] == "event") { event = WorkflowEventItem().deserialize(j["element"]); } else { compute = null; data = null; processing = null; storage = null; workflow = null; + event = null; } } else { compute = null; @@ -738,12 +748,13 @@ class GraphItem extends SerializerDeserializer { processing = null; storage = null; workflow = null; - } + event = null; + } } Map toDashboard() { Map element = {}; - List items = [data, processing, storage, compute, workflow]; + List items = [data, processing, storage, compute, workflow, event]; for(var el in items) { if (el != null && el.getID() != "") { element = el.serialize(); @@ -762,7 +773,7 @@ class GraphItem extends SerializerDeserializer { @override deserialize(dynamic json) { try { json = json as Map; - } catch (e) { return GraphItem(); } + } catch (e) { return GraphItem(); } return GraphItem( id: json.containsKey("id") ? json["id"] : null, width: json.containsKey("width") ? double.parse(json["width"].toString()) : null, @@ -773,9 +784,10 @@ class GraphItem extends SerializerDeserializer { storage: json.containsKey("storage") ? StorageItem().deserialize(json["storage"]) : null, compute: json.containsKey("compute") ? ComputeItem().deserialize(json["compute"]) : null, workflow: json.containsKey("workflow") ? WorkflowItem().deserialize(json["workflow"]) : null, + event: json.containsKey("event") ? WorkflowEventItem().deserialize(json["event"]) : null, ); } - @override Map serialize() { + @override Map serialize() { return { "id": id, "width": width, @@ -785,6 +797,7 @@ class GraphItem extends SerializerDeserializer { "storage": storage?.serialize(), "compute": compute?.serialize(), "workflow": workflow?.serialize(), + "event": event?.serialize(), "position": position?.serialize(), }; } diff --git a/lib/pages/catalog_item.dart b/lib/pages/catalog_item.dart index cf6b1a3..898ccc4 100644 --- a/lib/pages/catalog_item.dart +++ b/lib/pages/catalog_item.dart @@ -37,7 +37,7 @@ class CatalogItemFactory implements AbstractFactory { if (special) { return; } // T var s = SearchConstants.get(); AppRouter.catalog.go(context, {}); - Future.delayed(Duration(milliseconds: 10), () { + Future.delayed(const Duration(milliseconds: 10), () { SearchConstants.set(s); CatalogFactory().search(context, false); }); diff --git a/lib/pages/workflow.dart b/lib/pages/workflow.dart index 150e4de..e025235 100644 --- a/lib/pages/workflow.dart +++ b/lib/pages/workflow.dart @@ -12,12 +12,15 @@ import 'package:oc_front/models/resources/processing.dart'; import 'package:oc_front/models/resources/resources.dart'; import 'package:oc_front/models/resources/storage.dart'; import 'package:oc_front/models/resources/workflow.dart'; +import 'package:oc_front/models/resources/workflow_event.dart'; import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/abstract_page.dart'; import 'package:oc_front/pages/shared.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:oc_front/widgets/dialog/shallow_creation.dart'; import 'package:oc_front/widgets/forms/resource_forms.dart'; +import 'package:oc_front/widgets/forms/workflow_event_forms.dart'; import 'package:oc_front/widgets/forms/scheduler_forms.dart'; import 'package:oc_front/widgets/forms/storage_processing_link_forms.dart'; import 'package:oc_front/widgets/items/item_row.dart'; @@ -52,9 +55,15 @@ class WorkflowPageWidgetState extends State { final WorflowService _service = WorflowService(); Widget itemBuild(Object item) { var e = item as AbstractItem; + if (e is WorkflowEventItem) { + return Tooltip( + message: e.name ?? "Event", + child: SvgPicture.asset('assets/images/workflow_event.svg', fit: BoxFit.contain), + ); + } return Tooltip( message: item.name ?? "", - child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill) - : Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', + child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill) + : Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', fit: BoxFit.fill)); } Widget itemTooltipBuild(Object item) { @@ -75,8 +84,13 @@ final WorflowService _service = WorflowService(); List getForms(FlowData? obj, String id) { var objAbs = obj as AbstractItem?; if (objAbs == null) { return []; } - List res = [ ResourceFormsWidget(item: objAbs, dash: dash, elementID: id) ]; - return [ Wrap( + List res; + if (objAbs is WorkflowEventItem) { + res = [ WorkflowEventFormsWidget(item: objAbs, dash: dash, elementID: id) ]; + } else { + res = [ ResourceFormsWidget(item: objAbs, dash: dash, elementID: id) ]; + } + return [ Wrap( alignment: WrapAlignment.center, children: [ Container( padding: const EdgeInsets.all(10), width: 250, height: 60, @@ -84,7 +98,7 @@ final WorflowService _service = WorflowService(); child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("ELEMENT INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Text("", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), - ])), + ])), ...res ]) ]; } @@ -124,6 +138,8 @@ final WorflowService _service = WorflowService(); return const Icon(FontAwesomeIcons.microchip, size: 16); } else if (objAbs.topic == "workflows" ) { return const Icon(FontAwesomeIcons.diagramProject, size: 16); + } else if (objAbs.topic == "event" ) { + return const Icon(FontAwesomeIcons.bolt, size: 16); } return null; } @@ -167,6 +183,7 @@ final WorflowService _service = WorflowService(); var storage = dash.elements.where( (e) => e.element?.serialize()["type"] == "storage"); var processing = dash.elements.where( (e) => e.element?.serialize()["type"] == "processing"); var workflows = dash.elements.where( (e) => e.element?.serialize()["type"] == "workflow"); + var events = dash.elements.where( (e) => e.element?.serialize()["type"] == "event"); var updateW = Workflow( name: dash.name, graph: Graph(), @@ -175,6 +192,7 @@ final WorflowService _service = WorflowService(); storage: storage.map((e) => e.element?.getID()).toSet().toList(), processing: processing.map((e) => e.element?.getID()).toSet().toList(), workflows: workflows.map((e) => e.element?.getID()).toSet().toList(), + events: events.map((e) => e.element?.getID()).toSet().toList(), ); updateW.fromDashboard(dash.serialize()); for (var item in (updateW.graph?.items.values ?? [] as List)) { @@ -210,6 +228,7 @@ final WorflowService _service = WorflowService(); if (data["type"] == "storage") { return StorageItem().deserialize(data); } if (data["type"] == "processing") { return ProcessingItem().deserialize(data); } if (data["type"] == "workflows") { return WorkflowItem().deserialize(data); } + if (data["type"] == "event") { return WorkflowEventItem().deserialize(data); } return null; } @@ -339,8 +358,13 @@ final WorflowService _service = WorflowService(); current: widget.id, itemWidget: itemBuild, menuWidget: onDashboardMenu, - categories: const ["processing", "data", "compute", "storage", "workflows"], - draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, false), + categories: const ["processing", "data", "compute", "storage", "workflows", "event"], + draggableItemBuilder: (cat) { + if (cat == "event") { + return [ WorkflowEventItem()..name = "Event"..type = "event" ]; + } + return WorkspaceLocal.byTopic(cat, false); + }, itemWidgetTooltip: itemTooltipBuild, innerMenuWidth: 350, width: getMainWidth(context), diff --git a/lib/widgets/dialog/login.dart b/lib/widgets/dialog/login.dart index eda7360..a322eba 100644 --- a/lib/widgets/dialog/login.dart +++ b/lib/widgets/dialog/login.dart @@ -2,12 +2,14 @@ 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'; +import 'package:oc_front/core/services/oauth2.service.dart'; import 'package:oc_front/main.dart'; import 'package:oc_front/pages/workflow.dart'; +// ignore: must_be_immutable class LoginWidget extends StatefulWidget { - LoginWidget ({ Key? key }): super(key: key); + String? loginChallenge; + LoginWidget ({ super.key, required this.loginChallenge }); @override LoginWidgetState createState() => LoginWidgetState(); } class LoginWidgetState extends State { @@ -18,7 +20,8 @@ class LoginWidgetState extends State { bool loading = false; FocusNode focusNode = FocusNode(); @override Widget build(BuildContext context) { - return KeyboardListener(focusNode: focusNode, + return KeyboardListener( + focusNode: focusNode, onKeyEvent: (value) async { if (value is KeyDownEvent && value.logicalKey == LogicalKeyboardKey.enter) { if (usernameCtrl.text == "" || passwordCtrl.text == "") { return; } @@ -26,7 +29,7 @@ class LoginWidgetState extends State { setState(() { loading = true; }); - await AuthService.login(usernameCtrl.text, passwordCtrl.text).catchError( (e) { + await OAuth2Service().login(usernameCtrl.text, passwordCtrl.text, widget.loginChallenge ?? '').catchError( (e) { setState(() { loading = false; error = "Invalid username or password"; @@ -47,8 +50,8 @@ class LoginWidgetState extends State { }, child: Container( padding: const EdgeInsets.all(50), child: Column(children: [ getMainHeight(context) < 600 ? Container() : SizedBox( width: getMainWidth(context) / 4, height: getMainHeight(context) / 4, - child: FittedBox( - child:const Center(child: Icon(Icons.person_search, size: 150, color: Colors.grey,)))), + child: const FittedBox( + child:Center(child: Icon(Icons.person_search, size: 150, color: Colors.grey,)))), Center(child: Padding( padding: const EdgeInsets.only(top: 5, bottom: 20), child: Text("WELCOME ON OPENCLOUD", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: lightColor ), overflow: TextOverflow.ellipsis, ))), @@ -107,7 +110,7 @@ class LoginWidgetState extends State { setState(() { loading = true; }); - await AuthService.login(usernameCtrl.text, passwordCtrl.text).catchError( (e) { + await OAuth2Service().login(usernameCtrl.text, passwordCtrl.text, widget.loginChallenge ?? '').catchError( (e) { setState(() { loading = false; error = "Invalid username or password"; diff --git a/lib/widgets/forms/workflow_event_forms.dart b/lib/widgets/forms/workflow_event_forms.dart new file mode 100644 index 0000000..d24a1f3 --- /dev/null +++ b/lib/widgets/forms/workflow_event_forms.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_flow_chart/flutter_flow_chart.dart'; +import 'package:oc_front/core/services/specialized_services/workflow_service.dart'; +import 'package:oc_front/models/resources/workflow_event.dart'; + +// ignore: must_be_immutable +class WorkflowEventFormsWidget extends StatefulWidget { + WorkflowEventItem item; + Dashboard dash; + String elementID; + WorkflowEventFormsWidget({ + super.key, + required this.item, + required this.dash, + required this.elementID, + }); + @override WorkflowEventFormsWidgetState createState() => WorkflowEventFormsWidgetState(); +} + +class WorkflowEventFormsWidgetState extends State { + final WorflowService _service = WorflowService(); + + Future>> _loadWorkflows() async { + List> items = []; + await _service.all(null).then((response) { + if (response.data != null) { + for (var entry in response.data!.values) { + final id = entry["id"]?.toString() ?? ""; + final name = entry["name"]?.toString() ?? id; + if (id.isEmpty) continue; + items.add(DropdownMenuItem(value: id, child: Text(name, overflow: TextOverflow.ellipsis))); + } + } + }); + return items; + } + + @override Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 8), + child: Text("Workflow cible", style: TextStyle(fontSize: 12, color: Colors.grey)), + ), + FutureBuilder>>( + future: _loadWorkflows(), + builder: (context, snapshot) { + final items = snapshot.data ?? []; + final current = items.any((e) => e.value == widget.item.workflowExecutionId) + ? widget.item.workflowExecutionId + : null; + return DropdownButtonFormField( + isExpanded: true, + value: current, + hint: const Text("Sélectionner un workflow...", style: TextStyle(fontSize: 12)), + style: const TextStyle(fontSize: 12, color: Colors.black, overflow: TextOverflow.ellipsis), + decoration: const InputDecoration( + fillColor: Colors.white, + filled: true, + labelText: "workflow", + labelStyle: TextStyle(fontSize: 10), + floatingLabelBehavior: FloatingLabelBehavior.always, + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + items: items, + onChanged: (value) { + if (value == null) return; + setState(() { + widget.item.workflowExecutionId = value; + widget.item.id = value; + }); + widget.dash.notifyListeners(); + }, + ); + }, + ), + ], + ), + ); + } +} diff --git a/library/flutter_flow_chart/.dart_tool/package_config.json b/library/flutter_flow_chart/.dart_tool/package_config.json index b98484b..61a564c 100644 --- a/library/flutter_flow_chart/.dart_tool/package_config.json +++ b/library/flutter_flow_chart/.dart_tool/package_config.json @@ -69,7 +69,7 @@ }, { "name": "flutter", - "rootUri": "file:///home/mr/snap/flutter/common/flutter/packages/flutter", + "rootUri": "file:///home/mr/flutter/packages/flutter", "packageUri": "lib/", "languageVersion": "3.3" }, @@ -87,16 +87,10 @@ }, { "name": "flutter_test", - "rootUri": "file:///home/mr/snap/flutter/common/flutter/packages/flutter_test", + "rootUri": "file:///home/mr/flutter/packages/flutter_test", "packageUri": "lib/", "languageVersion": "3.3" }, - { - "name": "hover_menu", - "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/hover_menu-1.1.1", - "packageUri": "lib/", - "languageVersion": "2.16" - }, { "name": "leak_tracker", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/leak_tracker-10.0.5", @@ -147,7 +141,7 @@ }, { "name": "sky_engine", - "rootUri": "file:///home/mr/snap/flutter/common/flutter/bin/cache/pkg/sky_engine", + "rootUri": "file:///home/mr/flutter/bin/cache/pkg/sky_engine", "packageUri": "lib/", "languageVersion": "3.2" }, @@ -230,10 +224,10 @@ "languageVersion": "3.3" } ], - "generated": "2025-02-17T08:57:16.568019Z", + "generated": "2026-02-11T13:07:02.110119Z", "generator": "pub", "generatorVersion": "3.5.3", - "flutterRoot": "file:///home/mr/snap/flutter/common/flutter", + "flutterRoot": "file:///home/mr/flutter", "flutterVersion": "3.24.3", "pubCache": "file:///home/mr/.pub-cache" } diff --git a/library/flutter_flow_chart/.dart_tool/package_config_subset b/library/flutter_flow_chart/.dart_tool/package_config_subset index 76b530e..24f257f 100644 --- a/library/flutter_flow_chart/.dart_tool/package_config_subset +++ b/library/flutter_flow_chart/.dart_tool/package_config_subset @@ -50,10 +50,6 @@ flutter_colorpicker 2.14 file:///home/mr/.pub-cache/hosted/pub.dev/flutter_colorpicker-1.1.0/ file:///home/mr/.pub-cache/hosted/pub.dev/flutter_colorpicker-1.1.0/lib/ -hover_menu -2.16 -file:///home/mr/.pub-cache/hosted/pub.dev/hover_menu-1.1.1/ -file:///home/mr/.pub-cache/hosted/pub.dev/hover_menu-1.1.1/lib/ leak_tracker 3.2 file:///home/mr/.pub-cache/hosted/pub.dev/leak_tracker-10.0.5/ @@ -140,14 +136,14 @@ file:///home/mr/Documents/OC/oc-front/library/flutter_flow_chart/ file:///home/mr/Documents/OC/oc-front/library/flutter_flow_chart/lib/ sky_engine 3.2 -file:///home/mr/snap/flutter/common/flutter/bin/cache/pkg/sky_engine/ -file:///home/mr/snap/flutter/common/flutter/bin/cache/pkg/sky_engine/lib/ +file:///home/mr/flutter/bin/cache/pkg/sky_engine/ +file:///home/mr/flutter/bin/cache/pkg/sky_engine/lib/ flutter 3.3 -file:///home/mr/snap/flutter/common/flutter/packages/flutter/ -file:///home/mr/snap/flutter/common/flutter/packages/flutter/lib/ +file:///home/mr/flutter/packages/flutter/ +file:///home/mr/flutter/packages/flutter/lib/ flutter_test 3.3 -file:///home/mr/snap/flutter/common/flutter/packages/flutter_test/ -file:///home/mr/snap/flutter/common/flutter/packages/flutter_test/lib/ +file:///home/mr/flutter/packages/flutter_test/ +file:///home/mr/flutter/packages/flutter_test/lib/ 2 diff --git a/library/flutter_flow_chart/pubspec.lock b/library/flutter_flow_chart/pubspec.lock index 988a33a..b27ed6a 100644 --- a/library/flutter_flow_chart/pubspec.lock +++ b/library/flutter_flow_chart/pubspec.lock @@ -115,14 +115,6 @@ packages: description: flutter source: sdk version: "0.0.0" - hover_menu: - dependency: "direct main" - description: - name: hover_menu - sha256: "73d68be1d63462da1fbaa0b6d57cd6939b324b714bb64559b4a1240ec780a9b0" - url: "https://pub.dev" - source: hosted - version: "1.1.1" leak_tracker: dependency: transitive description: @@ -289,5 +281,5 @@ packages: source: hosted version: "14.2.5" sdks: - dart: ">=3.3.0 <=3.7.12" + dart: ">=3.3.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/library/flutter_flow_chart/pubspec.yaml b/library/flutter_flow_chart/pubspec.yaml index 6824c96..3519ea1 100755 --- a/library/flutter_flow_chart/pubspec.yaml +++ b/library/flutter_flow_chart/pubspec.yaml @@ -17,7 +17,6 @@ dependencies: # https://pub.dev/packages/uuid flutter_box_transform: ^0.4.4 flutter_colorpicker: ^1.1.0 - hover_menu: ^1.1.1 number_text_input_formatter: ^1.0.0+8 uuid: ^4.4.0 diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index accb2a5..d0e7f79 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,18 +6,10 @@ #include "generated_plugin_registrant.h" -#include -#include -#include +#include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) desktop_window_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWindowPlugin"); - desktop_window_plugin_register_with_registrar(desktop_window_registrar); - g_autoptr(FlPluginRegistrar) irondash_engine_context_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "IrondashEngineContextPlugin"); - irondash_engine_context_plugin_register_with_registrar(irondash_engine_context_registrar); - g_autoptr(FlPluginRegistrar) super_native_extensions_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "SuperNativeExtensionsPlugin"); - super_native_extensions_plugin_register_with_registrar(super_native_extensions_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index b735452..b29e9ba 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,9 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST - desktop_window - irondash_engine_context - super_native_extensions + flutter_secure_storage_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index d003d19..6770fb5 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,18 +5,14 @@ import FlutterMacOS import Foundation -import desktop_window -import device_info_plus -import irondash_engine_context +import flutter_appauth +import flutter_secure_storage_darwin import path_provider_foundation import shared_preferences_foundation -import super_native_extensions func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - DesktopWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWindowPlugin")) - DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) - IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin")) + FlutterAppauthPlugin.register(with: registry.registrar(forPlugin: "FlutterAppauthPlugin")) + FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) - SuperNativeExtensionsPlugin.register(with: registry.registrar(forPlugin: "SuperNativeExtensionsPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 2b0c312..396de5e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,14 +9,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" - animated_toggle_switch: - dependency: "direct main" - description: - name: animated_toggle_switch - sha256: "786e82be3b004100299c1c6d023f8f1928decc8353a6fdff191bf78c866262fa" - url: "https://pub.dev" - source: hosted - version: "0.8.3" args: dependency: transitive description: @@ -97,14 +89,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" dart_earcut: dependency: transitive description: @@ -114,7 +98,7 @@ packages: source: hosted version: "1.1.0" dashed_path: - dependency: "direct main" + dependency: transitive description: name: dashed_path sha256: "711cb86eb57e023e8ad9199ea717eaf0be0906743a884c261fbe2711dc12fe9d" @@ -129,30 +113,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" - desktop_window: - dependency: "direct main" - description: - name: desktop_window - sha256: cb30b3bcea10931a21333ed044f85054cf9242820f3c240264a4c0df324a9fd6 - url: "https://pub.dev" - source: hosted - version: "0.4.1" - device_info_plus: - dependency: transitive - description: - name: device_info_plus - sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 - url: "https://pub.dev" - source: hosted - version: "10.1.2" - device_info_plus_platform_interface: - dependency: transitive - description: - name: device_info_plus_platform_interface - sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" - url: "https://pub.dev" - source: hosted - version: "7.0.1" dio: dependency: "direct main" description: @@ -177,14 +137,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.3" - el_tooltip: - dependency: "direct main" - description: - name: el_tooltip - sha256: "0860b00e9390a31dd98369dc16d3b6fa2668fc52df712bd00e86d8931787fc17" - url: "https://pub.dev" - source: hosted - version: "2.2.1" fake_async: dependency: transitive description: @@ -230,6 +182,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + flutter_appauth: + dependency: "direct main" + description: + name: flutter_appauth + sha256: b09fa8e3eaba12ec341c69ec45063e06eb565304e24cc35caaf105bbae2e955c + url: "https://pub.dev" + source: hosted + version: "9.0.1" + flutter_appauth_platform_interface: + dependency: transitive + description: + name: flutter_appauth_platform_interface + sha256: fd2920b853d09741aff2e1178e044ea2ade0c87799cd8e63f094ab35b00fdf70 + url: "https://pub.dev" + source: hosted + version: "9.0.0" flutter_box_transform: dependency: "direct main" description: @@ -246,14 +214,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - flutter_event_calendar: - dependency: "direct main" - description: - name: flutter_event_calendar - sha256: f5b6f22ae01c24a1fc3f6432d3080130bb40efc976e53941b5f6422b6a4f9d64 - url: "https://pub.dev" - source: hosted - version: "1.0.0" flutter_flow_chart: dependency: "direct main" description: @@ -277,6 +237,54 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.2" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + sha256: da922f2aab2d733db7e011a6bcc4a825b844892d4edd6df83ff156b09a9b2e40 + url: "https://pub.dev" + source: hosted + version: "10.0.0" + flutter_secure_storage_darwin: + dependency: transitive + description: + name: flutter_secure_storage_darwin + sha256: "8878c25136a79def1668c75985e8e193d9d7d095453ec28730da0315dc69aee3" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: "2b5c76dce569ab752d55a1cee6a2242bcc11fdba927078fb88c503f150767cda" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: "8ceea1223bee3c6ac1a22dabd8feefc550e4729b3675de4b5900f55afcb435d6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: "6a1137df62b84b54261dca582c1c09ea72f4f9a4b2fcee21b025964132d5d0c3" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: "3b7c8e068875dfd46719ff57c90d8c459c87f2302ed6b00ff006b3c9fcad1613" + url: "https://pub.dev" + source: hosted + version: "4.1.0" flutter_spinkit: dependency: "direct main" description: @@ -311,14 +319,6 @@ packages: url: "https://pub.dev" source: hosted version: "10.8.0" - get_it: - dependency: transitive - description: - name: get_it - sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 - url: "https://pub.dev" - source: hosted - version: "7.7.0" go_router: dependency: "direct main" description: @@ -327,14 +327,6 @@ packages: url: "https://pub.dev" source: hosted version: "14.3.0" - hover_menu: - dependency: "direct main" - description: - name: hover_menu - sha256: "73d68be1d63462da1fbaa0b6d57cd6939b324b714bb64559b4a1240ec780a9b0" - url: "https://pub.dev" - source: hosted - version: "1.1.1" http: dependency: transitive description: @@ -351,14 +343,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" - injectable: - dependency: "direct main" - description: - name: injectable - sha256: "3c8355a29d11ff28c0311bed754649761f345ef7a13ff66a714380954af51226" - url: "https://pub.dev" - source: hosted - version: "2.4.2" intl: dependency: "direct main" description: @@ -367,22 +351,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.19.0" - irondash_engine_context: - dependency: transitive - description: - name: irondash_engine_context - sha256: cd7b769db11a2b5243b037c8a9b1ecaef02e1ae27a2d909ffa78c1dad747bb10 - url: "https://pub.dev" - source: hosted - version: "0.5.4" - irondash_message_channel: - dependency: transitive - description: - name: irondash_message_channel - sha256: b4101669776509c76133b8917ab8cfc704d3ad92a8c450b92934dd8884a2f060 - url: "https://pub.dev" - source: hosted - version: "0.7.0" json_string: dependency: "direct main" description: @@ -399,6 +367,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + jwt_decoder: + dependency: "direct main" + description: + name: jwt_decoder + sha256: "54774aebf83f2923b99e6416b4ea915d47af3bde56884eb622de85feabbc559f" + url: "https://pub.dev" + source: hosted + version: "2.0.1" latlong2: dependency: "direct main" description: @@ -411,26 +387,26 @@ 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: @@ -483,18 +459,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: @@ -528,7 +504,7 @@ packages: source: hosted version: "1.0.1" path_provider: - dependency: "direct main" + dependency: transitive description: name: path_provider sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 @@ -583,14 +559,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" - pixel_snap: - dependency: transitive - description: - name: pixel_snap - sha256: "677410ea37b07cd37ecb6d5e6c0d8d7615a7cf3bd92ba406fd1ac57e937d1fb0" - url: "https://pub.dev" - source: hosted - version: "0.1.5" platform: dependency: transitive description: @@ -623,22 +591,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" - scoped_model: - dependency: transitive - description: - name: scoped_model - sha256: "8dacc77cb5de78d5e159d54cab883847491a73dfaa3d28c52f4ec8b0be32645b" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - shamsi_date: - dependency: transitive - description: - name: shamsi_date - sha256: "5df195a0b7794b7d4a8dc9321244400147896def157b7530c5b8a2f9cfc6a7a4" - url: "https://pub.dev" - source: hosted - version: "0.15.0" shared_preferences: dependency: "direct main" description: @@ -732,14 +684,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.1" - star_menu: - dependency: "direct main" - description: - name: star_menu - sha256: f29c7d255677c49ec2412ec2d17220d967f54b72b9e6afc5688fe122ea4d1d78 - url: "https://pub.dev" - source: hosted - version: "4.0.1" stream_channel: dependency: transitive description: @@ -756,54 +700,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - super_clipboard: - dependency: transitive - description: - name: super_clipboard - sha256: "74098001413e075cc53dee72b68c32eaffc10709df41806800393abaa6dac9d5" - url: "https://pub.dev" - source: hosted - version: "0.8.19" - super_drag_and_drop: - dependency: "direct main" - description: - name: super_drag_and_drop - sha256: "20f4318a6c9e81a76cc090a0f2d845157ff4f3619ed784e3235324a45ce34507" - url: "https://pub.dev" - source: hosted - version: "0.8.19" - super_native_extensions: - dependency: transitive - description: - name: super_native_extensions - sha256: c24676825c9f3ae844676a843d45ad186f2270539ffe72be4277753e46d14e29 - url: "https://pub.dev" - source: hosted - version: "0.8.19" - syncfusion_flutter_calendar: - dependency: "direct main" - description: - name: syncfusion_flutter_calendar - sha256: "1fdbcb8435abc4a1fb36914b83d9690eb0dea617df3ac2772519fba7a3011828" - url: "https://pub.dev" - source: hosted - version: "27.1.55" - syncfusion_flutter_core: - dependency: transitive - description: - name: syncfusion_flutter_core - sha256: bc86234c9a0a87b6c3288b9065175e74e9a73e22b2237989a8bbdeff0c8befd7 - url: "https://pub.dev" - source: hosted - version: "27.1.55" - syncfusion_flutter_datepicker: - dependency: transitive - description: - name: syncfusion_flutter_datepicker - sha256: "54fe7e7a660ecdf072cceec890425d7531b42f647245f9244565c61e96fbca4a" - url: "https://pub.dev" - source: hosted - version: "27.1.55" table_calendar: dependency: "direct main" description: @@ -824,18 +720,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" - timezone: - dependency: transitive - description: - name: timezone - sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" - url: "https://pub.dev" - source: hosted - version: "0.9.4" + version: "0.7.2" typed_data: dependency: transitive description: @@ -896,10 +784,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: @@ -912,18 +800,10 @@ packages: dependency: transitive description: name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" + sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e url: "https://pub.dev" source: hosted - version: "5.5.0" - win32_registry: - dependency: transitive - description: - name: win32_registry - sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb" - url: "https://pub.dev" - source: hosted - version: "1.1.3" + version: "5.10.1" wkt_parser: dependency: transitive description: @@ -949,5 +829,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.3.4 <=3.7.12" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index b83e6e1..912325c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,7 +19,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.3.4 <4.0.0' + sdk: '>=3.4.0 <4.0.0' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -31,11 +31,9 @@ dependencies: flutter: sdk: flutter - + jwt_decoder: ^2.0.1 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.6 - desktop_window: ^0.4.0 flutter_svg: ^2.0.10+1 go_router: ^14.2.0 shared_preferences: ^2.2.3 @@ -44,33 +42,25 @@ dependencies: latlong2: ^0.9.1 dio: ^5.5.0 alert_banner: ^1.0.1 - injectable: ^2.4.2 convert: ^3.1.1 flutter_flow_chart: path: ./library/flutter_flow_chart - star_menu: ^4.0.1 - path_provider: ^2.1.3 - super_drag_and_drop: ^0.8.17 uuid: ^4.4.0 box_transform: ^0.4.4 flutter_box_transform: ^0.4.4 - animated_toggle_switch: ^0.8.2 - el_tooltip: ^2.0.0 - dashed_path: ^1.0.1 dotted_line: ^3.2.2 number_text_input_formatter: ^1.0.0+8 flutter_colorpicker: ^1.1.0 - hover_menu: ^1.1.1 datetime_picker_formfield: ^2.0.1 intl: ^0.19.0 flutter_advanced_switch: ^3.1.0 cron: ^0.6.1 - flutter_event_calendar: ^1.0.0 - syncfusion_flutter_calendar: ^27.1.55 json_string: ^3.0.1 flutter_spinkit: ^5.2.1 localstorage: ^5.0.0 font_awesome_flutter: ^10.8.0 + flutter_appauth: ^9.0.1 + flutter_secure_storage: ^10.0.0 dev_dependencies: flutter_test: @@ -97,6 +87,7 @@ flutter: assets: - assets/images/logo.svg - assets/images/icon.svg + - assets/images/workflow_event.svg - assets/config/front.json # To add assets to your application, add an assets section, like this: # assets: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 66231d8..0c50753 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,15 +6,9 @@ #include "generated_plugin_registrant.h" -#include -#include -#include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { - DesktopWindowPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("DesktopWindowPlugin")); - IrondashEngineContextPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi")); - SuperNativeExtensionsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SuperNativeExtensionsPluginCApi")); + FlutterSecureStorageWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index a9370dd..4fc759c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,9 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST - desktop_window - irondash_engine_context - super_native_extensions + flutter_secure_storage_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST