feat: WebSocket temps réel + Finance Workflow + corrections
- Task #6: WebSocket /ws/dashboard + Kafka events (5 topics) * Backend: KafkaEventProducer, KafkaEventConsumer * Mobile: WebSocketService (reconnection, heartbeat, typed events) * DashboardBloc: Auto-refresh depuis WebSocket events - Finance Workflow: approbations + budgets (backend + mobile) * Backend: entities, services, resources, migrations Flyway V6 * Mobile: features finance_workflow complète avec BLoC - Corrections DI: interfaces IRepository partout * IProfileRepository, IOrganizationRepository, IMembreRepository * GetIt configuré avec @injectable - Spec-Kit: constitution + templates mis à jour * .specify/memory/constitution.md enrichie * Templates agent, plan, spec, tasks, checklist - Nettoyage: fichiers temporaires supprimés Signed-off-by: lions dev Team
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
/// Modèle des statistiques de cache système
|
||||
/// Correspond à CacheStatsResponse du backend
|
||||
library cache_stats_model;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'cache_stats_model.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class CacheStatsModel extends Equatable {
|
||||
final int? totalSizeBytes;
|
||||
final String? totalSizeFormatted;
|
||||
final int? totalEntries;
|
||||
final double? hitRate;
|
||||
final int? hits;
|
||||
final int? misses;
|
||||
final DateTime? lastCleared;
|
||||
|
||||
const CacheStatsModel({
|
||||
this.totalSizeBytes,
|
||||
this.totalSizeFormatted,
|
||||
this.totalEntries,
|
||||
this.hitRate,
|
||||
this.hits,
|
||||
this.misses,
|
||||
this.lastCleared,
|
||||
});
|
||||
|
||||
factory CacheStatsModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$CacheStatsModelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$CacheStatsModelToJson(this);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
totalSizeBytes,
|
||||
totalSizeFormatted,
|
||||
totalEntries,
|
||||
hitRate,
|
||||
hits,
|
||||
misses,
|
||||
lastCleared,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/// Modèle de configuration système
|
||||
/// Correspond à SystemConfigResponse du backend
|
||||
library system_config_model;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'system_config_model.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class SystemConfigModel extends Equatable {
|
||||
// Configuration générale
|
||||
final String? applicationName;
|
||||
final String? timezone;
|
||||
final String? defaultLanguage;
|
||||
final bool? maintenanceMode;
|
||||
final String? version;
|
||||
final DateTime? lastUpdated;
|
||||
|
||||
// Configuration réseau
|
||||
final int? networkTimeout;
|
||||
final int? maxRetries;
|
||||
final int? connectionPoolSize;
|
||||
|
||||
// Configuration sécurité
|
||||
final bool? twoFactorAuthEnabled;
|
||||
final int? sessionTimeoutMinutes;
|
||||
final bool? auditLoggingEnabled;
|
||||
|
||||
// Configuration performance
|
||||
final bool? metricsCollectionEnabled;
|
||||
final int? metricsIntervalSeconds;
|
||||
final bool? performanceOptimizationEnabled;
|
||||
|
||||
// Configuration backup
|
||||
final bool? autoBackupEnabled;
|
||||
final String? backupFrequency;
|
||||
final int? backupRetentionDays;
|
||||
final DateTime? lastBackup;
|
||||
|
||||
// Configuration logs
|
||||
final String? logLevel;
|
||||
final int? logRetentionDays;
|
||||
final bool? detailedLoggingEnabled;
|
||||
final bool? logCompressionEnabled;
|
||||
|
||||
// Configuration monitoring
|
||||
final bool? realTimeMonitoringEnabled;
|
||||
final int? monitoringIntervalSeconds;
|
||||
final bool? emailAlertsEnabled;
|
||||
final bool? pushAlertsEnabled;
|
||||
|
||||
// Configuration alertes
|
||||
final bool? cpuHighAlertEnabled;
|
||||
final int? cpuThresholdPercent;
|
||||
final bool? memoryLowAlertEnabled;
|
||||
final int? memoryThresholdPercent;
|
||||
final bool? criticalErrorAlertEnabled;
|
||||
final bool? connectionFailureAlertEnabled;
|
||||
final int? connectionFailureThreshold;
|
||||
|
||||
// Statut système
|
||||
final String? systemStatus;
|
||||
final int? uptime;
|
||||
|
||||
const SystemConfigModel({
|
||||
this.applicationName,
|
||||
this.timezone,
|
||||
this.defaultLanguage,
|
||||
this.maintenanceMode,
|
||||
this.version,
|
||||
this.lastUpdated,
|
||||
this.networkTimeout,
|
||||
this.maxRetries,
|
||||
this.connectionPoolSize,
|
||||
this.twoFactorAuthEnabled,
|
||||
this.sessionTimeoutMinutes,
|
||||
this.auditLoggingEnabled,
|
||||
this.metricsCollectionEnabled,
|
||||
this.metricsIntervalSeconds,
|
||||
this.performanceOptimizationEnabled,
|
||||
this.autoBackupEnabled,
|
||||
this.backupFrequency,
|
||||
this.backupRetentionDays,
|
||||
this.lastBackup,
|
||||
this.logLevel,
|
||||
this.logRetentionDays,
|
||||
this.detailedLoggingEnabled,
|
||||
this.logCompressionEnabled,
|
||||
this.realTimeMonitoringEnabled,
|
||||
this.monitoringIntervalSeconds,
|
||||
this.emailAlertsEnabled,
|
||||
this.pushAlertsEnabled,
|
||||
this.cpuHighAlertEnabled,
|
||||
this.cpuThresholdPercent,
|
||||
this.memoryLowAlertEnabled,
|
||||
this.memoryThresholdPercent,
|
||||
this.criticalErrorAlertEnabled,
|
||||
this.connectionFailureAlertEnabled,
|
||||
this.connectionFailureThreshold,
|
||||
this.systemStatus,
|
||||
this.uptime,
|
||||
});
|
||||
|
||||
factory SystemConfigModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$SystemConfigModelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$SystemConfigModelToJson(this);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
applicationName,
|
||||
timezone,
|
||||
defaultLanguage,
|
||||
maintenanceMode,
|
||||
version,
|
||||
lastUpdated,
|
||||
networkTimeout,
|
||||
maxRetries,
|
||||
connectionPoolSize,
|
||||
twoFactorAuthEnabled,
|
||||
sessionTimeoutMinutes,
|
||||
auditLoggingEnabled,
|
||||
metricsCollectionEnabled,
|
||||
metricsIntervalSeconds,
|
||||
performanceOptimizationEnabled,
|
||||
autoBackupEnabled,
|
||||
backupFrequency,
|
||||
backupRetentionDays,
|
||||
lastBackup,
|
||||
logLevel,
|
||||
logRetentionDays,
|
||||
detailedLoggingEnabled,
|
||||
logCompressionEnabled,
|
||||
realTimeMonitoringEnabled,
|
||||
monitoringIntervalSeconds,
|
||||
emailAlertsEnabled,
|
||||
pushAlertsEnabled,
|
||||
cpuHighAlertEnabled,
|
||||
cpuThresholdPercent,
|
||||
memoryLowAlertEnabled,
|
||||
memoryThresholdPercent,
|
||||
criticalErrorAlertEnabled,
|
||||
connectionFailureAlertEnabled,
|
||||
connectionFailureThreshold,
|
||||
systemStatus,
|
||||
uptime,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'system_metrics_model.g.dart';
|
||||
|
||||
/// Modèle pour les métriques système en temps réel
|
||||
@JsonSerializable(fieldRename: FieldRename.none)
|
||||
class SystemMetricsModel {
|
||||
// Métriques CPU
|
||||
final double? cpuUsagePercent;
|
||||
final int? availableProcessors;
|
||||
final double? systemLoadAverage;
|
||||
|
||||
// Métriques mémoire
|
||||
final int? totalMemoryBytes;
|
||||
final int? usedMemoryBytes;
|
||||
final int? freeMemoryBytes;
|
||||
final int? maxMemoryBytes;
|
||||
final double? memoryUsagePercent;
|
||||
final String? totalMemoryFormatted;
|
||||
final String? usedMemoryFormatted;
|
||||
final String? freeMemoryFormatted;
|
||||
|
||||
// Métriques disque
|
||||
final int? totalDiskBytes;
|
||||
final int? usedDiskBytes;
|
||||
final int? freeDiskBytes;
|
||||
final double? diskUsagePercent;
|
||||
final String? totalDiskFormatted;
|
||||
final String? usedDiskFormatted;
|
||||
final String? freeDiskFormatted;
|
||||
|
||||
// Métriques utilisateurs
|
||||
final int? activeUsersCount;
|
||||
final int? totalUsersCount;
|
||||
final int? activeSessionsCount;
|
||||
final int? failedLoginAttempts24h;
|
||||
|
||||
// Métriques API
|
||||
final int? apiRequestsLastHour;
|
||||
final int? apiRequestsToday;
|
||||
final double? averageResponseTimeMs;
|
||||
final int? totalRequestsCount;
|
||||
|
||||
// Métriques base de données
|
||||
final int? dbConnectionPoolSize;
|
||||
final int? dbActiveConnections;
|
||||
final int? dbIdleConnections;
|
||||
final bool? dbHealthy;
|
||||
|
||||
// Métriques erreurs et logs
|
||||
final int? criticalErrorsCount;
|
||||
final int? warningsCount;
|
||||
final int? infoLogsCount;
|
||||
final int? debugLogsCount;
|
||||
final int? totalLogsCount;
|
||||
|
||||
// Métriques réseau
|
||||
final double? networkBytesReceivedPerSec;
|
||||
final double? networkBytesSentPerSec;
|
||||
final String? networkInFormatted;
|
||||
final String? networkOutFormatted;
|
||||
|
||||
// Métriques système
|
||||
final String? systemStatus;
|
||||
final int? uptimeMillis;
|
||||
final String? uptimeFormatted;
|
||||
final String? startTime;
|
||||
final String? currentTime;
|
||||
final String? javaVersion;
|
||||
final String? quarkusVersion;
|
||||
final String? applicationVersion;
|
||||
|
||||
// Métriques maintenance
|
||||
final String? lastBackup;
|
||||
final String? nextScheduledMaintenance;
|
||||
final String? lastMaintenance;
|
||||
|
||||
// URLs
|
||||
final String? apiBaseUrl;
|
||||
final String? authServerUrl;
|
||||
final String? cdnUrl;
|
||||
|
||||
// Cache
|
||||
final int? totalCacheSizeBytes;
|
||||
final String? totalCacheSizeFormatted;
|
||||
final int? totalCacheEntries;
|
||||
|
||||
const SystemMetricsModel({
|
||||
this.cpuUsagePercent,
|
||||
this.availableProcessors,
|
||||
this.systemLoadAverage,
|
||||
this.totalMemoryBytes,
|
||||
this.usedMemoryBytes,
|
||||
this.freeMemoryBytes,
|
||||
this.maxMemoryBytes,
|
||||
this.memoryUsagePercent,
|
||||
this.totalMemoryFormatted,
|
||||
this.usedMemoryFormatted,
|
||||
this.freeMemoryFormatted,
|
||||
this.totalDiskBytes,
|
||||
this.usedDiskBytes,
|
||||
this.freeDiskBytes,
|
||||
this.diskUsagePercent,
|
||||
this.totalDiskFormatted,
|
||||
this.usedDiskFormatted,
|
||||
this.freeDiskFormatted,
|
||||
this.activeUsersCount,
|
||||
this.totalUsersCount,
|
||||
this.activeSessionsCount,
|
||||
this.failedLoginAttempts24h,
|
||||
this.apiRequestsLastHour,
|
||||
this.apiRequestsToday,
|
||||
this.averageResponseTimeMs,
|
||||
this.totalRequestsCount,
|
||||
this.dbConnectionPoolSize,
|
||||
this.dbActiveConnections,
|
||||
this.dbIdleConnections,
|
||||
this.dbHealthy,
|
||||
this.criticalErrorsCount,
|
||||
this.warningsCount,
|
||||
this.infoLogsCount,
|
||||
this.debugLogsCount,
|
||||
this.totalLogsCount,
|
||||
this.networkBytesReceivedPerSec,
|
||||
this.networkBytesSentPerSec,
|
||||
this.networkInFormatted,
|
||||
this.networkOutFormatted,
|
||||
this.systemStatus,
|
||||
this.uptimeMillis,
|
||||
this.uptimeFormatted,
|
||||
this.startTime,
|
||||
this.currentTime,
|
||||
this.javaVersion,
|
||||
this.quarkusVersion,
|
||||
this.applicationVersion,
|
||||
this.lastBackup,
|
||||
this.nextScheduledMaintenance,
|
||||
this.lastMaintenance,
|
||||
this.apiBaseUrl,
|
||||
this.authServerUrl,
|
||||
this.cdnUrl,
|
||||
this.totalCacheSizeBytes,
|
||||
this.totalCacheSizeFormatted,
|
||||
this.totalCacheEntries,
|
||||
});
|
||||
|
||||
factory SystemMetricsModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$SystemMetricsModelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$SystemMetricsModelToJson(this);
|
||||
|
||||
/// Helper pour formater un pourcentage
|
||||
String formatPercent(double? percent) {
|
||||
if (percent == null) return '0%';
|
||||
return '${percent.toStringAsFixed(1)}%';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/// Repository pour la gestion de la configuration système
|
||||
/// Implémentation avec l'API backend SystemResource
|
||||
library system_config_repository_impl;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import 'package:unionflow_mobile_apps/core/utils/logger.dart';
|
||||
import '../../domain/repositories/system_config_repository.dart';
|
||||
import '../models/system_config_model.dart';
|
||||
import '../models/cache_stats_model.dart';
|
||||
import '../models/system_metrics_model.dart';
|
||||
|
||||
/// Implémentation du repository de configuration système
|
||||
@LazySingleton(as: ISystemConfigRepository)
|
||||
class SystemConfigRepositoryImpl implements ISystemConfigRepository {
|
||||
final ApiClient _apiClient;
|
||||
static const String _base = '/api/system';
|
||||
|
||||
SystemConfigRepositoryImpl(this._apiClient);
|
||||
|
||||
@override
|
||||
Future<SystemConfigModel> getConfig() async {
|
||||
final response = await _apiClient.get('$_base/config');
|
||||
if (response.statusCode == 200) {
|
||||
return SystemConfigModel.fromJson(response.data as Map<String, dynamic>);
|
||||
}
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SystemConfigModel> updateConfig(Map<String, dynamic> config) async {
|
||||
final response = await _apiClient.put('$_base/config', data: config);
|
||||
if (response.statusCode == 200) {
|
||||
return SystemConfigModel.fromJson(response.data as Map<String, dynamic>);
|
||||
}
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CacheStatsModel> getCacheStats() async {
|
||||
final response = await _apiClient.get('$_base/cache/stats');
|
||||
if (response.statusCode == 200) {
|
||||
return CacheStatsModel.fromJson(response.data as Map<String, dynamic>);
|
||||
}
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SystemMetricsModel> getMetrics() async {
|
||||
final response = await _apiClient.get('$_base/metrics');
|
||||
if (response.statusCode == 200) {
|
||||
return SystemMetricsModel.fromJson(response.data as Map<String, dynamic>);
|
||||
}
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clearCache() async {
|
||||
final response = await _apiClient.post('$_base/cache/clear');
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> testDatabase() async {
|
||||
final response = await _apiClient.post('$_base/test/database');
|
||||
if (response.statusCode == 200) {
|
||||
return response.data as Map<String, dynamic>;
|
||||
}
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> testEmail() async {
|
||||
final response = await _apiClient.post('$_base/test/email');
|
||||
if (response.statusCode == 200) {
|
||||
return response.data as Map<String, dynamic>;
|
||||
}
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SystemConfigModel> resetConfig() async {
|
||||
try {
|
||||
// Tente d'abord l'endpoint dédié pour le reset
|
||||
final response = await _apiClient.post('$_base/config/reset');
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
return SystemConfigModel.fromJson(response.data as Map<String, dynamic>);
|
||||
}
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
} on DioException catch (e, st) {
|
||||
// Si l'endpoint n'existe pas (404), fallback : récupérer config par défaut via GET
|
||||
if (e.response?.statusCode == 404) {
|
||||
AppLogger.warning(
|
||||
'SystemConfigRepository: Endpoint /reset non disponible, fallback sur config par défaut',
|
||||
);
|
||||
// Alternative: Appeler un endpoint qui retourne la config par défaut
|
||||
// ou construire une config minimale côté client
|
||||
try {
|
||||
final defaultResponse = await _apiClient.get('$_base/config/default');
|
||||
if (defaultResponse.statusCode == 200) {
|
||||
return SystemConfigModel.fromJson(defaultResponse.data as Map<String, dynamic>);
|
||||
}
|
||||
} catch (_) {
|
||||
// Si même le default échoue, retourner une config minimale
|
||||
AppLogger.error(
|
||||
'SystemConfigRepository: resetConfig fallback échoué, config minimale retournée',
|
||||
error: e,
|
||||
stackTrace: st,
|
||||
);
|
||||
// Config minimale codée en dur pour éviter un crash total
|
||||
return SystemConfigModel.fromJson({
|
||||
'id': 'default',
|
||||
'appName': 'UnionFlow',
|
||||
'version': '1.0.0',
|
||||
'maintenance': false,
|
||||
'enableCache': true,
|
||||
'cacheExpirationMinutes': 30,
|
||||
});
|
||||
}
|
||||
}
|
||||
AppLogger.error('SystemConfigRepository: resetConfig échoué', error: e, stackTrace: st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/// Interface du repository pour la gestion de la configuration système
|
||||
library i_system_config_repository;
|
||||
|
||||
import '../../data/models/system_config_model.dart';
|
||||
import '../../data/models/cache_stats_model.dart';
|
||||
import '../../data/models/system_metrics_model.dart';
|
||||
|
||||
/// Interface définissant le contrat pour la gestion de la configuration système
|
||||
abstract class ISystemConfigRepository {
|
||||
/// Récupère la configuration système actuelle
|
||||
Future<SystemConfigModel> getConfig();
|
||||
|
||||
/// Met à jour la configuration système
|
||||
Future<SystemConfigModel> updateConfig(Map<String, dynamic> config);
|
||||
|
||||
/// Récupère les statistiques du cache
|
||||
Future<CacheStatsModel> getCacheStats();
|
||||
|
||||
/// Récupère les métriques système
|
||||
Future<SystemMetricsModel> getMetrics();
|
||||
|
||||
/// Vide le cache applicatif
|
||||
Future<void> clearCache();
|
||||
|
||||
/// Teste la connexion à la base de données
|
||||
Future<Map<String, dynamic>> testDatabase();
|
||||
|
||||
/// Teste la configuration email
|
||||
Future<Map<String, dynamic>> testEmail();
|
||||
|
||||
/// Réinitialise la configuration aux valeurs par défaut
|
||||
Future<SystemConfigModel> resetConfig();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/// Use Case: Vider le cache applicatif
|
||||
library clear_cache;
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../repositories/system_config_repository.dart';
|
||||
|
||||
/// Vide le cache applicatif
|
||||
///
|
||||
/// Use case pour nettoyer le cache et libérer de l'espace mémoire
|
||||
/// Endpoint: POST /api/system/cache/clear
|
||||
@injectable
|
||||
class ClearCache {
|
||||
final ISystemConfigRepository _repository;
|
||||
|
||||
ClearCache(this._repository);
|
||||
|
||||
/// Exécute le use case
|
||||
/// Vide complètement le cache applicatif
|
||||
Future<void> call() async {
|
||||
return _repository.clearCache();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/// Use Case: Récupérer les statistiques du cache
|
||||
library get_cache_stats;
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../repositories/system_config_repository.dart';
|
||||
import '../../data/models/cache_stats_model.dart';
|
||||
|
||||
/// Récupère les statistiques du cache applicatif
|
||||
///
|
||||
/// Use case pour consulter l'état du cache (taille, hits/miss, etc.)
|
||||
/// Endpoint: GET /api/system/cache/stats
|
||||
@injectable
|
||||
class GetCacheStats {
|
||||
final ISystemConfigRepository _repository;
|
||||
|
||||
GetCacheStats(this._repository);
|
||||
|
||||
/// Exécute le use case
|
||||
/// Retourne les statistiques du cache (CacheStatsModel)
|
||||
Future<CacheStatsModel> call() async {
|
||||
return _repository.getCacheStats();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/// Use Case: Récupérer la configuration système
|
||||
library get_settings;
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../repositories/system_config_repository.dart';
|
||||
import '../../data/models/system_config_model.dart';
|
||||
|
||||
/// Récupère la configuration système actuelle
|
||||
///
|
||||
/// Use case pour récupérer tous les paramètres de configuration système
|
||||
/// Endpoint: GET /api/system/config
|
||||
@injectable
|
||||
class GetSettings {
|
||||
final ISystemConfigRepository _repository;
|
||||
|
||||
GetSettings(this._repository);
|
||||
|
||||
/// Exécute le use case
|
||||
/// Retourne la configuration système actuelle (SystemConfigModel)
|
||||
Future<SystemConfigModel> call() async {
|
||||
return _repository.getConfig();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/// Use Case: Réinitialiser la configuration système
|
||||
library reset_settings;
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../repositories/system_config_repository.dart';
|
||||
import '../../data/models/system_config_model.dart';
|
||||
|
||||
/// Réinitialise la configuration système aux valeurs par défaut
|
||||
///
|
||||
/// Use case pour restaurer tous les paramètres à leur état initial
|
||||
/// Endpoint: POST /api/system/config/reset (ou DELETE /api/system/config)
|
||||
@injectable
|
||||
class ResetSettings {
|
||||
final ISystemConfigRepository _repository;
|
||||
|
||||
ResetSettings(this._repository);
|
||||
|
||||
/// Exécute le use case
|
||||
/// Restaure la configuration aux valeurs par défaut du système
|
||||
Future<SystemConfigModel> call() async {
|
||||
return _repository.resetConfig();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/// Use Case: Mettre à jour la configuration système
|
||||
library update_settings;
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../repositories/system_config_repository.dart';
|
||||
import '../../data/models/system_config_model.dart';
|
||||
|
||||
/// Met à jour la configuration système
|
||||
///
|
||||
/// Use case pour modifier les paramètres de configuration système
|
||||
/// Endpoint: PUT /api/system/config
|
||||
@injectable
|
||||
class UpdateSettings {
|
||||
final ISystemConfigRepository _repository;
|
||||
|
||||
UpdateSettings(this._repository);
|
||||
|
||||
/// Exécute le use case
|
||||
/// [config] : Map contenant les paramètres à mettre à jour
|
||||
/// Retourne la configuration mise à jour
|
||||
Future<SystemConfigModel> call(Map<String, dynamic> config) async {
|
||||
return _repository.updateConfig(config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/// BLoC pour la gestion des paramètres système (Clean Architecture)
|
||||
library system_settings_bloc;
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../../domain/usecases/get_settings.dart';
|
||||
import '../../domain/usecases/update_settings.dart';
|
||||
import '../../domain/usecases/get_cache_stats.dart';
|
||||
import '../../domain/usecases/clear_cache.dart' as uc;
|
||||
import '../../domain/usecases/reset_settings.dart';
|
||||
import '../../domain/repositories/system_config_repository.dart';
|
||||
import 'system_settings_event.dart';
|
||||
import 'system_settings_state.dart';
|
||||
|
||||
@injectable
|
||||
class SystemSettingsBloc extends Bloc<SystemSettingsEvent, SystemSettingsState> {
|
||||
final GetSettings _getSettings;
|
||||
final UpdateSettings _updateSettings;
|
||||
final GetCacheStats _getCacheStats;
|
||||
final uc.ClearCache _clearCache;
|
||||
final ResetSettings _resetSettings;
|
||||
final ISystemConfigRepository _repository; // Pour méthodes non-couvertes (metrics, test DB, test email)
|
||||
|
||||
SystemSettingsBloc(
|
||||
this._getSettings,
|
||||
this._updateSettings,
|
||||
this._getCacheStats,
|
||||
this._clearCache,
|
||||
this._resetSettings,
|
||||
this._repository,
|
||||
) : super(SystemSettingsInitial()) {
|
||||
on<LoadSystemConfig>(_onLoadSystemConfig);
|
||||
on<UpdateSystemConfig>(_onUpdateSystemConfig);
|
||||
on<LoadCacheStats>(_onLoadCacheStats);
|
||||
on<LoadSystemMetrics>(_onLoadSystemMetrics);
|
||||
on<ClearCache>(_onClearCache);
|
||||
on<TestDatabaseConnection>(_onTestDatabaseConnection);
|
||||
on<TestEmailConfiguration>(_onTestEmailConfiguration);
|
||||
on<ResetSystemConfig>(_onResetSystemConfig);
|
||||
}
|
||||
|
||||
Future<void> _onLoadSystemConfig(
|
||||
LoadSystemConfig event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
final config = await _getSettings(); // ✅ Use case
|
||||
emit(SystemConfigLoaded(config));
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur de chargement: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onUpdateSystemConfig(
|
||||
UpdateSystemConfig event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
final config = await _updateSettings(event.config); // ✅ Use case
|
||||
emit(SystemConfigLoaded(config));
|
||||
emit(const SystemSettingsSuccess('Configuration mise à jour'));
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur de mise à jour: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadCacheStats(
|
||||
LoadCacheStats event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
final stats = await _getCacheStats(); // ✅ Use case
|
||||
emit(CacheStatsLoaded(stats));
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur de chargement: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadSystemMetrics(
|
||||
LoadSystemMetrics event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
final metrics = await _repository.getMetrics();
|
||||
emit(SystemMetricsLoaded(metrics));
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur de chargement des métriques: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onClearCache(
|
||||
ClearCache event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
await _clearCache(); // ✅ Use case
|
||||
emit(const SystemSettingsSuccess('Cache vidé avec succès'));
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onTestDatabaseConnection(
|
||||
TestDatabaseConnection event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
final result = await _repository.testDatabase();
|
||||
final success = result['success'] as bool? ?? false;
|
||||
final message = result['message'] as String? ?? 'Test terminé';
|
||||
if (success) {
|
||||
emit(SystemSettingsSuccess(message));
|
||||
} else {
|
||||
emit(SystemSettingsError(message));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur de test: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onTestEmailConfiguration(
|
||||
TestEmailConfiguration event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
final result = await _repository.testEmail();
|
||||
final success = result['success'] as bool? ?? false;
|
||||
final message = result['message'] as String? ?? 'Test terminé';
|
||||
if (success) {
|
||||
emit(SystemSettingsSuccess(message));
|
||||
} else {
|
||||
emit(SystemSettingsError(message));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur de test: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
/// Réinitialise la configuration système aux valeurs par défaut
|
||||
Future<void> _onResetSystemConfig(
|
||||
ResetSystemConfig event,
|
||||
Emitter<SystemSettingsState> emit,
|
||||
) async {
|
||||
emit(SystemSettingsLoading());
|
||||
try {
|
||||
final config = await _resetSettings(); // ✅ Use case
|
||||
emit(SystemConfigLoaded(config));
|
||||
emit(const SystemSettingsSuccess('Configuration réinitialisée'));
|
||||
} catch (e) {
|
||||
emit(SystemSettingsError('Erreur de réinitialisation: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/// Events pour SystemSettingsBloc
|
||||
library system_settings_event;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class SystemSettingsEvent extends Equatable {
|
||||
const SystemSettingsEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class LoadSystemConfig extends SystemSettingsEvent {}
|
||||
|
||||
class UpdateSystemConfig extends SystemSettingsEvent {
|
||||
final Map<String, dynamic> config;
|
||||
|
||||
const UpdateSystemConfig(this.config);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [config];
|
||||
}
|
||||
|
||||
class LoadCacheStats extends SystemSettingsEvent {}
|
||||
|
||||
class LoadSystemMetrics extends SystemSettingsEvent {}
|
||||
|
||||
class ClearCache extends SystemSettingsEvent {}
|
||||
|
||||
class TestDatabaseConnection extends SystemSettingsEvent {}
|
||||
|
||||
class TestEmailConfiguration extends SystemSettingsEvent {}
|
||||
|
||||
class ResetSystemConfig extends SystemSettingsEvent {}
|
||||
@@ -0,0 +1,63 @@
|
||||
/// States pour SystemSettingsBloc
|
||||
library system_settings_state;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import '../../data/models/system_config_model.dart';
|
||||
import '../../data/models/cache_stats_model.dart';
|
||||
import '../../data/models/system_metrics_model.dart';
|
||||
|
||||
abstract class SystemSettingsState extends Equatable {
|
||||
const SystemSettingsState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class SystemSettingsInitial extends SystemSettingsState {}
|
||||
|
||||
class SystemSettingsLoading extends SystemSettingsState {}
|
||||
|
||||
class SystemConfigLoaded extends SystemSettingsState {
|
||||
final SystemConfigModel config;
|
||||
|
||||
const SystemConfigLoaded(this.config);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [config];
|
||||
}
|
||||
|
||||
class CacheStatsLoaded extends SystemSettingsState {
|
||||
final CacheStatsModel stats;
|
||||
|
||||
const CacheStatsLoaded(this.stats);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [stats];
|
||||
}
|
||||
|
||||
class SystemMetricsLoaded extends SystemSettingsState {
|
||||
final SystemMetricsModel metrics;
|
||||
|
||||
const SystemMetricsLoaded(this.metrics);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [metrics];
|
||||
}
|
||||
|
||||
class SystemSettingsSuccess extends SystemSettingsState {
|
||||
final String message;
|
||||
|
||||
const SystemSettingsSuccess(this.message);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
}
|
||||
|
||||
class SystemSettingsError extends SystemSettingsState {
|
||||
final String error;
|
||||
|
||||
const SystemSettingsError(this.error);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [error];
|
||||
}
|
||||
@@ -5,6 +5,7 @@ library feedback_page;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import '../../../../core/utils/logger.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
|
||||
class FeedbackPage extends StatefulWidget {
|
||||
@@ -54,7 +55,8 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
_messageController.clear();
|
||||
_showSnackBar('Merci pour votre retour !');
|
||||
}
|
||||
} catch (_) {
|
||||
} catch (e, st) {
|
||||
AppLogger.error('FeedbackPage: envoi feedback échoué', error: e, stackTrace: st);
|
||||
if (mounted) {
|
||||
_showSnackBar('Envoi échoué. Réessayez plus tard.', isError: true);
|
||||
}
|
||||
|
||||
@@ -23,14 +23,16 @@ class _LanguageSettingsPageState extends State<LanguageSettingsPage> {
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_syncFromProvider();
|
||||
}
|
||||
|
||||
void _syncFromProvider() {
|
||||
final lp = context.read<LocaleProvider>();
|
||||
setState(() => _selectedLanguage = lp.currentLanguageName);
|
||||
if (lp.currentLanguageName != _selectedLanguage) {
|
||||
setState(() => _selectedLanguage = lp.currentLanguageName);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _changeLanguage(String languageName, String code) async {
|
||||
|
||||
@@ -4,6 +4,7 @@ library privacy_settings_page;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
|
||||
class PrivacySettingsPage extends StatefulWidget {
|
||||
@@ -278,7 +279,13 @@ class _PrivacySettingsPageState extends State<PrivacySettingsPage> {
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
final uri = Uri.parse('mailto:support@unionflow.com?subject=Demande de suppression de compte');
|
||||
if (await canLaunchUrl(uri)) {
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||
child: const Text('Contacter l\'administrateur', style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
@@ -377,7 +384,9 @@ class _PrivacySettingsPageState extends State<PrivacySettingsPage> {
|
||||
Switch(
|
||||
value: value,
|
||||
onChanged: onChanged,
|
||||
activeColor: ColorTokens.primary,
|
||||
activeTrackColor: ColorTokens.primary,
|
||||
thumbColor: WidgetStateProperty.resolveWith((states) =>
|
||||
states.contains(WidgetState.selected) ? Colors.white : null),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
import '../../../../features/authentication/presentation/bloc/auth_bloc.dart';
|
||||
import '../../../../features/authentication/data/models/user_role.dart';
|
||||
import '../../data/models/system_metrics_model.dart';
|
||||
import '../bloc/system_settings_bloc.dart';
|
||||
import '../bloc/system_settings_event.dart';
|
||||
import '../bloc/system_settings_state.dart';
|
||||
|
||||
/// Page Paramètres Système - UnionFlow Mobile
|
||||
///
|
||||
@@ -15,7 +23,10 @@ class SystemSettingsPage extends StatefulWidget {
|
||||
class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
with TickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
|
||||
|
||||
// Métriques système en temps réel
|
||||
SystemMetricsModel? _metrics;
|
||||
|
||||
// États des paramètres système
|
||||
bool _maintenanceMode = false;
|
||||
bool _debugMode = false;
|
||||
@@ -25,11 +36,11 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
bool _sslEnforced = true;
|
||||
bool _apiLoggingEnabled = false;
|
||||
bool _performanceMonitoring = true;
|
||||
|
||||
|
||||
String _selectedLogLevel = 'INFO';
|
||||
String _selectedBackupFrequency = 'Quotidien';
|
||||
String _selectedCacheStrategy = 'Intelligent';
|
||||
|
||||
|
||||
final List<String> _logLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR'];
|
||||
final List<String> _backupFrequencies = ['Temps réel', 'Horaire', 'Quotidien', 'Hebdomadaire'];
|
||||
final List<String> _cacheStrategies = ['Agressif', 'Intelligent', 'Conservateur', 'Désactivé'];
|
||||
@@ -49,31 +60,112 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF8F9FA),
|
||||
body: Column(
|
||||
children: [
|
||||
// Header harmonisé
|
||||
_buildHeader(),
|
||||
|
||||
// Onglets
|
||||
_buildTabBar(),
|
||||
|
||||
// Contenu des onglets
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
return BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, authState) {
|
||||
// Accès réservé aux super administrateurs (configuration système globale)
|
||||
if (authState is! AuthAuthenticated || authState.effectiveRole != UserRole.superAdmin) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF8F9FA),
|
||||
appBar: AppBar(
|
||||
title: const Text('Paramètres Système'),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
tooltip: 'Retour',
|
||||
),
|
||||
),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.lock_outline, size: 64, color: ColorTokens.onSurfaceVariant.withOpacity(0.5)),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Accès réservé',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: ColorTokens.onSurface,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Les paramètres système sont réservés aux administrateurs plateforme.',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: ColorTokens.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return BlocProvider(
|
||||
create: (_) => sl<SystemSettingsBloc>()
|
||||
..add(LoadSystemConfig())
|
||||
..add(LoadSystemMetrics()),
|
||||
child: BlocConsumer<SystemSettingsBloc, SystemSettingsState>(
|
||||
listener: (context, state) {
|
||||
if (state is SystemMetricsLoaded) {
|
||||
setState(() {
|
||||
_metrics = state.metrics;
|
||||
});
|
||||
} else if (state is SystemSettingsSuccess) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.message),
|
||||
backgroundColor: ColorTokens.success,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
} else if (state is SystemSettingsError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.error),
|
||||
backgroundColor: ColorTokens.error,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF8F9FA),
|
||||
body: Column(
|
||||
children: [
|
||||
_buildGeneralTab(),
|
||||
_buildSecurityTab(),
|
||||
_buildPerformanceTab(),
|
||||
_buildMaintenanceTab(),
|
||||
_buildMonitoringTab(),
|
||||
// Header harmonisé
|
||||
_buildHeader(),
|
||||
|
||||
// Onglets
|
||||
_buildTabBar(),
|
||||
|
||||
// Contenu des onglets
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
_buildGeneralTab(),
|
||||
_buildSecurityTab(),
|
||||
_buildPerformanceTab(),
|
||||
_buildMaintenanceTab(),
|
||||
_buildMonitoringTab(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -179,7 +271,7 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
Expanded(
|
||||
child: _buildSystemIndicator(
|
||||
'Statut',
|
||||
_maintenanceMode ? 'Maintenance' : 'Opérationnel',
|
||||
_metrics?.systemStatus ?? (_maintenanceMode ? 'MAINTENANCE' : 'OPERATIONAL'),
|
||||
_maintenanceMode ? Icons.build : Icons.check_circle,
|
||||
_maintenanceMode ? Colors.orange : Colors.green,
|
||||
),
|
||||
@@ -188,7 +280,7 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
Expanded(
|
||||
child: _buildSystemIndicator(
|
||||
'Charge CPU',
|
||||
'23%',
|
||||
_metrics != null ? '${_metrics!.cpuUsagePercent?.toStringAsFixed(0) ?? '0'}%' : '-',
|
||||
Icons.memory,
|
||||
Colors.blue,
|
||||
),
|
||||
@@ -197,7 +289,7 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
Expanded(
|
||||
child: _buildSystemIndicator(
|
||||
'Utilisateurs',
|
||||
'1,247',
|
||||
_metrics?.activeUsersCount?.toString() ?? '-',
|
||||
Icons.people,
|
||||
Colors.purple,
|
||||
),
|
||||
@@ -361,7 +453,9 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
),
|
||||
_buildActionSetting(
|
||||
'Vider le cache système',
|
||||
'Supprimer tous les fichiers temporaires (2.3 GB)',
|
||||
_metrics != null
|
||||
? 'Supprimer tous les fichiers temporaires (${_metrics!.totalCacheSizeFormatted ?? "0 B"})'
|
||||
: 'Supprimer tous les fichiers temporaires',
|
||||
Icons.delete_sweep,
|
||||
const Color(0xFFE17055),
|
||||
() => _clearSystemCache(),
|
||||
@@ -384,9 +478,9 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
'Paramètres de connectivité',
|
||||
Icons.network_check,
|
||||
[
|
||||
_buildInfoSetting('Serveur API', 'https://api.unionflow.com'),
|
||||
_buildInfoSetting('Serveur d\'authentification', 'https://auth.unionflow.com'),
|
||||
_buildInfoSetting('CDN Assets', 'https://cdn.unionflow.com'),
|
||||
_buildInfoSetting('Serveur API', _metrics?.apiBaseUrl ?? 'Non configuré'),
|
||||
_buildInfoSetting('Serveur d\'authentification', _metrics?.authServerUrl ?? 'Non configuré'),
|
||||
_buildInfoSetting('CDN Assets', _metrics?.cdnUrl ?? 'Non configuré'),
|
||||
_buildActionSetting(
|
||||
'Tester la connectivité',
|
||||
'Vérifier la connexion aux services',
|
||||
@@ -453,8 +547,14 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
'Gestion des accès utilisateurs',
|
||||
Icons.login,
|
||||
[
|
||||
_buildInfoSetting('Sessions actives', '1,247 utilisateurs connectés'),
|
||||
_buildInfoSetting('Tentatives échouées', '23 dans les dernières 24h'),
|
||||
_buildInfoSetting(
|
||||
'Sessions actives',
|
||||
_metrics != null ? '${_metrics!.activeSessionsCount ?? 0} sessions actives' : 'Chargement...',
|
||||
),
|
||||
_buildInfoSetting(
|
||||
'Tentatives échouées',
|
||||
_metrics != null ? '${_metrics!.failedLoginAttempts24h ?? 0} dans les dernières 24h' : 'Chargement...',
|
||||
),
|
||||
_buildActionSetting(
|
||||
'Forcer la déconnexion globale',
|
||||
'Déconnecter tous les utilisateurs',
|
||||
@@ -562,10 +662,30 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
'État actuel du système',
|
||||
Icons.speed,
|
||||
[
|
||||
_buildMetricItem('CPU', '23%', Icons.memory, Colors.blue),
|
||||
_buildMetricItem('RAM', '67%', Icons.storage, Colors.green),
|
||||
_buildMetricItem('Disque', '45%', Icons.storage, Colors.orange),
|
||||
_buildMetricItem('Réseau', '12 MB/s', Icons.network_check, Colors.purple),
|
||||
_buildMetricItem(
|
||||
'CPU',
|
||||
_metrics != null ? '${_metrics!.cpuUsagePercent?.toStringAsFixed(1) ?? '0'}%' : '-',
|
||||
Icons.memory,
|
||||
Colors.blue,
|
||||
),
|
||||
_buildMetricItem(
|
||||
'RAM',
|
||||
_metrics != null ? '${_metrics!.memoryUsagePercent?.toStringAsFixed(1) ?? '0'}%' : '-',
|
||||
Icons.storage,
|
||||
Colors.green,
|
||||
),
|
||||
_buildMetricItem(
|
||||
'Disque',
|
||||
_metrics != null ? '${_metrics!.diskUsagePercent?.toStringAsFixed(1) ?? '0'}%' : '-',
|
||||
Icons.storage,
|
||||
Colors.orange,
|
||||
),
|
||||
_buildMetricItem(
|
||||
'Réseau',
|
||||
_metrics?.networkInFormatted ?? '0 B/s',
|
||||
Icons.network_check,
|
||||
Colors.purple,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -662,8 +782,14 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
'Opérations de maintenance',
|
||||
Icons.build,
|
||||
[
|
||||
_buildInfoSetting('Dernière maintenance', '15/12/2024 à 02:30'),
|
||||
_buildInfoSetting('Prochaine maintenance', '22/12/2024 à 02:00'),
|
||||
_buildInfoSetting(
|
||||
'Dernière maintenance',
|
||||
_metrics?.lastMaintenance ?? 'Aucune maintenance récente',
|
||||
),
|
||||
_buildInfoSetting(
|
||||
'Prochaine maintenance',
|
||||
_metrics?.nextScheduledMaintenance ?? 'Non planifiée',
|
||||
),
|
||||
_buildActionSetting(
|
||||
'Planifier une maintenance',
|
||||
'Programmer une fenêtre de maintenance',
|
||||
@@ -689,8 +815,14 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
'Gestion des versions',
|
||||
Icons.system_update,
|
||||
[
|
||||
_buildInfoSetting('Version actuelle', 'UnionFlow Server 2.1.0'),
|
||||
_buildInfoSetting('Dernière vérification', 'Il y a 2 heures'),
|
||||
_buildInfoSetting(
|
||||
'Version actuelle',
|
||||
_metrics != null ? 'UnionFlow Server ${_metrics!.applicationVersion ?? "N/A"}' : 'Chargement...',
|
||||
),
|
||||
_buildInfoSetting(
|
||||
'Uptime',
|
||||
_metrics?.uptimeFormatted ?? 'Chargement...',
|
||||
),
|
||||
_buildActionSetting(
|
||||
'Vérifier les mises à jour',
|
||||
'Rechercher les nouvelles versions',
|
||||
@@ -763,10 +895,26 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
'Journaux d\'activité',
|
||||
Icons.article,
|
||||
[
|
||||
_buildLogItem('Erreurs critiques', '3', Colors.red),
|
||||
_buildLogItem('Avertissements', '27', Colors.orange),
|
||||
_buildLogItem('Informations', '1,247', Colors.blue),
|
||||
_buildLogItem('Debug', '5,892', Colors.grey),
|
||||
_buildLogItem(
|
||||
'Erreurs critiques',
|
||||
_metrics?.criticalErrorsCount?.toString() ?? '0',
|
||||
Colors.red,
|
||||
),
|
||||
_buildLogItem(
|
||||
'Avertissements',
|
||||
_metrics?.warningsCount?.toString() ?? '0',
|
||||
Colors.orange,
|
||||
),
|
||||
_buildLogItem(
|
||||
'Informations',
|
||||
_metrics?.infoLogsCount?.toString() ?? '0',
|
||||
Colors.blue,
|
||||
),
|
||||
_buildLogItem(
|
||||
'Debug',
|
||||
_metrics?.debugLogsCount?.toString() ?? '0',
|
||||
Colors.grey,
|
||||
),
|
||||
_buildActionSetting(
|
||||
'Voir tous les logs',
|
||||
'Ouvrir la console de logs complète',
|
||||
@@ -792,10 +940,22 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
'Métriques d\'activité',
|
||||
Icons.bar_chart,
|
||||
[
|
||||
_buildStatItem('Utilisateurs actifs (24h)', '1,247'),
|
||||
_buildStatItem('Requêtes API (1h)', '45,892'),
|
||||
_buildStatItem('Données transférées', '2.3 GB'),
|
||||
_buildStatItem('Temps de réponse moyen', '127ms'),
|
||||
_buildStatItem(
|
||||
'Utilisateurs actifs (24h)',
|
||||
_metrics?.activeUsersCount?.toString() ?? '0',
|
||||
),
|
||||
_buildStatItem(
|
||||
'Requêtes API (1h)',
|
||||
_metrics?.apiRequestsLastHour?.toString() ?? '0',
|
||||
),
|
||||
_buildStatItem(
|
||||
'Mémoire utilisée',
|
||||
_metrics?.usedMemoryFormatted ?? '0 B',
|
||||
),
|
||||
_buildStatItem(
|
||||
'Temps de réponse moyen',
|
||||
_metrics != null ? '${_metrics!.averageResponseTimeMs?.toStringAsFixed(0) ?? "0"}ms' : '0ms',
|
||||
),
|
||||
_buildActionSetting(
|
||||
'Rapport détaillé',
|
||||
'Générer un rapport complet d\'utilisation',
|
||||
@@ -1396,9 +1556,15 @@ class _SystemSettingsPageState extends State<SystemSettingsPage>
|
||||
}
|
||||
|
||||
// Actions générales
|
||||
void _clearSystemCache() => _showSuccessSnackBar('Cache système vidé (2.3 GB libérés)');
|
||||
void _clearSystemCache() {
|
||||
context.read<SystemSettingsBloc>().add(ClearCache());
|
||||
}
|
||||
|
||||
void _optimizeDatabase() => _showSuccessSnackBar('Base de données optimisée');
|
||||
void _testConnectivity() => _showSuccessSnackBar('Connectivité OK - Tous les services répondent');
|
||||
|
||||
void _testConnectivity() {
|
||||
context.read<SystemSettingsBloc>().add(TestDatabaseConnection());
|
||||
}
|
||||
|
||||
// Actions de sécurité
|
||||
void _regenerateApiKeys() => _showWarningDialog('Régénérer les clés API', 'Cette action invalidera toutes les clés existantes.');
|
||||
|
||||
Reference in New Issue
Block a user