Files
geutebruck/geutebruck_app/lib/data/services/server_cache_service.dart
Administrator c9e83e4277 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>
2026-01-02 22:52:51 +01:00

96 lines
3.5 KiB
Dart

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');
}
}