xp_nix/xp_dashboard/lib/src/widgets/logs_card.dart

151 lines
4.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:xp_models/xp_models.dart';
import '../theme/app_theme.dart';
class LogsCard extends StatefulWidget {
final SystemLogResponse? logs;
final Future<void> Function({int count, LogLevel? level}) onRefresh;
const LogsCard({
super.key,
required this.logs,
required this.onRefresh,
});
@override
State<LogsCard> createState() => _LogsCardState();
}
class _LogsCardState extends State<LogsCard> {
LogLevel? _selectedLevel;
bool _isRefreshing = false;
Future<void> _refreshLogs() async {
setState(() {
_isRefreshing = true;
});
try {
await widget.onRefresh(count: 50, level: _selectedLevel);
} finally {
if (mounted) {
setState(() {
_isRefreshing = false;
});
}
}
}
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.article, color: AppTheme.primaryColor),
const SizedBox(width: 8),
Expanded(
child: Text(
'System Logs',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
),
DropdownButton<LogLevel?>(
value: _selectedLevel,
hint: const Text('All'),
items: [
const DropdownMenuItem<LogLevel?>(
value: null,
child: Text('All'),
),
...LogLevel.values.map((level) => DropdownMenuItem<LogLevel?>(
value: level,
child: Text(level.name.toUpperCase()),
)),
],
onChanged: (LogLevel? newLevel) {
setState(() {
_selectedLevel = newLevel;
});
_refreshLogs();
},
),
const SizedBox(width: 8),
IconButton(
icon: _isRefreshing
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.refresh),
onPressed: _isRefreshing ? null : _refreshLogs,
tooltip: 'Refresh Logs',
),
],
),
const SizedBox(height: 16),
Container(
height: 300,
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.shade300),
),
child: widget.logs == null
? const Center(child: CircularProgressIndicator())
: widget.logs!.logs.isEmpty
? const Center(child: Text('No logs available'))
: ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: widget.logs!.logs.length,
itemBuilder: (context, index) {
final log = widget.logs!.logs[index];
return _LogEntry(log: log);
},
),
),
],
),
),
);
}
}
class _LogEntry extends StatelessWidget {
final String log;
const _LogEntry({required this.log});
@override
Widget build(BuildContext context) {
final color = _getLogColor(log);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Text(
log,
style: TextStyle(
fontFamily: 'monospace',
fontSize: 12,
color: color,
),
),
);
}
Color _getLogColor(String logEntry) {
if (logEntry.contains('[ERROR]')) return AppTheme.errorColor;
if (logEntry.contains('[WARN]')) return AppTheme.warningColor;
if (logEntry.contains('[INFO]')) return AppTheme.infoColor;
if (logEntry.contains('[DEBUG]')) return Colors.grey;
return Colors.black87;
}
}