feat: Add compact table views with advanced filtering and batch operations
- Enhanced Flutter web app management in PowerShell scripts - Added Flutter web server to start-services.ps1 as 4th service - Updated stop-services.ps1 to stop Flutter web server - Improved service orchestration and startup sequence - Implemented server caching for improved resilience - Added ServerCacheService for browser localStorage caching - Server lists persist across service restarts - Automatic fallback to cached data when API unavailable - Action picker categories always visible regardless of server status - Redesigned Action Mappings view with compact table layout - Replaced card-based ListView with DataTable for higher density - Added real-time search across name, input, output, description - Implemented multi-filter support (status: enabled/disabled) - Added column sorting (name, input, output, status, executions) - Batch operations: select all/multiple, batch delete - Reduced row height from ~120px to 56px for better overview - Redesigned Servers Management view with compact table layout - Replaced card-based ListView with DataTable - Added search by alias, host, user - Multi-filter support (type: all/G-Core/GeViScope, status: all/enabled/disabled) - Column sorting (alias, host, user, type, status) - Batch operations: select all/multiple, batch delete - Color-coded type and status badges - Improved action picker dialog for GSC/G-Core actions - GSC and G-Core categories always visible - Server validation with clear error messages - Fixed duplicate checkbox issue in table headers - Debug logging for troubleshooting server parameter issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
95
geutebruck_app/lib/data/services/server_cache_service.dart
Normal file
95
geutebruck_app/lib/data/services/server_cache_service.dart
Normal file
@@ -0,0 +1,95 @@
|
||||
import 'dart:convert';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../models/action_template.dart';
|
||||
|
||||
/// Service for caching server lists to prevent categories from disappearing
|
||||
/// when SDK Bridge is temporarily unavailable during service restarts
|
||||
class ServerCacheService {
|
||||
static const String _gcoreServersKey = 'cached_gcore_servers';
|
||||
static const String _gscServersKey = 'cached_gsc_servers';
|
||||
static const String _cacheTimestampKey = 'server_cache_timestamp';
|
||||
|
||||
/// Save G-Core servers to cache
|
||||
static Future<void> cacheGCoreServers(List<ServerInfo> servers) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final json = jsonEncode(servers.map((s) => s.toJson()).toList());
|
||||
await prefs.setString(_gcoreServersKey, json);
|
||||
await prefs.setInt(_cacheTimestampKey, DateTime.now().millisecondsSinceEpoch);
|
||||
print('[ServerCache] Cached ${servers.length} G-Core servers');
|
||||
}
|
||||
|
||||
/// Save GSC servers to cache
|
||||
static Future<void> cacheGSCServers(List<ServerInfo> servers) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final json = jsonEncode(servers.map((s) => s.toJson()).toList());
|
||||
await prefs.setString(_gscServersKey, json);
|
||||
await prefs.setInt(_cacheTimestampKey, DateTime.now().millisecondsSinceEpoch);
|
||||
print('[ServerCache] Cached ${servers.length} GSC servers');
|
||||
}
|
||||
|
||||
/// Save both server lists
|
||||
static Future<void> cacheServers({
|
||||
required List<ServerInfo> gcoreServers,
|
||||
required List<ServerInfo> gscServers,
|
||||
}) async {
|
||||
await cacheGCoreServers(gcoreServers);
|
||||
await cacheGSCServers(gscServers);
|
||||
}
|
||||
|
||||
/// Load cached G-Core servers
|
||||
static Future<List<ServerInfo>> getCachedGCoreServers() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final json = prefs.getString(_gcoreServersKey);
|
||||
if (json == null) {
|
||||
print('[ServerCache] No cached G-Core servers found');
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
final list = jsonDecode(json) as List<dynamic>;
|
||||
final servers = list.map((item) => ServerInfo.fromJson(item as Map<String, dynamic>)).toList();
|
||||
print('[ServerCache] Loaded ${servers.length} cached G-Core servers');
|
||||
return servers;
|
||||
} catch (e) {
|
||||
print('[ServerCache] Error loading cached G-Core servers: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Load cached GSC servers
|
||||
static Future<List<ServerInfo>> getCachedGSCServers() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final json = prefs.getString(_gscServersKey);
|
||||
if (json == null) {
|
||||
print('[ServerCache] No cached GSC servers found');
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
final list = jsonDecode(json) as List<dynamic>;
|
||||
final servers = list.map((item) => ServerInfo.fromJson(item as Map<String, dynamic>)).toList();
|
||||
print('[ServerCache] Loaded ${servers.length} cached GSC servers');
|
||||
return servers;
|
||||
} catch (e) {
|
||||
print('[ServerCache] Error loading cached GSC servers: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cache age in milliseconds
|
||||
static Future<int?> getCacheAge() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final timestamp = prefs.getInt(_cacheTimestampKey);
|
||||
if (timestamp == null) return null;
|
||||
return DateTime.now().millisecondsSinceEpoch - timestamp;
|
||||
}
|
||||
|
||||
/// Clear all cached server data
|
||||
static Future<void> clearCache() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(_gcoreServersKey);
|
||||
await prefs.remove(_gscServersKey);
|
||||
await prefs.remove(_cacheTimestampKey);
|
||||
print('[ServerCache] Cache cleared');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user