feat(app): live terminal log console widget and service dynamic settings management
This commit is contained in:
@@ -6,6 +6,7 @@ import '../../../core/widgets/glass_container.dart';
|
||||
import '../../../core/widgets/status_badge.dart';
|
||||
import '../models/service_setting_dto.dart';
|
||||
import '../repositories/admin_repository.dart';
|
||||
import '../widgets/live_log_console.dart';
|
||||
|
||||
class ServiceDetailScreen extends StatefulWidget {
|
||||
final String serviceName;
|
||||
@@ -75,9 +76,20 @@ class _ServiceDetailScreenState extends State<ServiceDetailScreen> {
|
||||
Future<void> _saveSettings() async {
|
||||
setState(() => _isSaving = true);
|
||||
try {
|
||||
final payload = <String, String>{};
|
||||
final payload = <String, dynamic>{};
|
||||
_controllers.forEach((k, v) {
|
||||
payload[k] = v.text;
|
||||
final text = v.text.trim();
|
||||
if (text.toLowerCase() == 'true') {
|
||||
payload[k] = true;
|
||||
} else if (text.toLowerCase() == 'false') {
|
||||
payload[k] = false;
|
||||
} else if (int.tryParse(text) != null) {
|
||||
payload[k] = int.parse(text);
|
||||
} else if (double.tryParse(text) != null) {
|
||||
payload[k] = double.parse(text);
|
||||
} else {
|
||||
payload[k] = text;
|
||||
}
|
||||
});
|
||||
|
||||
await _repository.updateServiceSettings(widget.serviceName, payload);
|
||||
@@ -170,10 +182,13 @@ class _ServiceDetailScreenState extends State<ServiceDetailScreen> {
|
||||
..._settings.map((s) {
|
||||
final key = s.key;
|
||||
final desc = s.description;
|
||||
final type = s.type.toLowerCase();
|
||||
final controller = _controllers[key];
|
||||
if (controller == null) return const SizedBox.shrink();
|
||||
|
||||
final isBoolean = controller.text.toLowerCase() == 'true' || controller.text.toLowerCase() == 'false';
|
||||
final isBoolean = type == 'bool' ||
|
||||
controller.text.toLowerCase() == 'true' ||
|
||||
controller.text.toLowerCase() == 'false';
|
||||
|
||||
if (isBoolean) {
|
||||
final boolVal = controller.text.toLowerCase() == 'true';
|
||||
@@ -183,7 +198,11 @@ class _ServiceDetailScreenState extends State<ServiceDetailScreen> {
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.glassSurface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppTheme.glassBorder),
|
||||
border: Border.all(
|
||||
color: boolVal
|
||||
? AppTheme.primaryEmerald.withValues(alpha: 0.4)
|
||||
: AppTheme.glassBorder,
|
||||
),
|
||||
),
|
||||
child: SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
@@ -191,21 +210,31 @@ class _ServiceDetailScreenState extends State<ServiceDetailScreen> {
|
||||
subtitle: desc.isNotEmpty ? Text(desc, style: TextStyle(fontSize: 11, color: AppTheme.textMuted)) : null,
|
||||
value: boolVal,
|
||||
activeThumbColor: AppTheme.primaryEmerald,
|
||||
activeTrackColor: AppTheme.primaryEmerald.withValues(alpha: 0.3),
|
||||
onChanged: (val) => setState(() => controller.text = val.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final isNumeric = type == 'int' || type == 'double' || type == 'number' || type == 'decimal';
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 14),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
keyboardType: isNumeric
|
||||
? const TextInputType.numberWithOptions(decimal: true)
|
||||
: TextInputType.text,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
decoration: InputDecoration(
|
||||
labelText: _formatLabel(key),
|
||||
helperText: desc.isNotEmpty ? desc : null,
|
||||
helperMaxLines: 2,
|
||||
prefixIcon: Icon(Icons.tune_outlined, size: 18, color: AppTheme.primaryEmerald),
|
||||
prefixIcon: Icon(
|
||||
isNumeric ? Icons.numbers_outlined : Icons.tune_outlined,
|
||||
size: 18,
|
||||
color: AppTheme.primaryEmerald,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -236,6 +265,11 @@ class _ServiceDetailScreenState extends State<ServiceDetailScreen> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
LiveLogConsole(
|
||||
serviceName: widget.serviceName,
|
||||
apiClient: widget.apiClient,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
GlassContainer(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
|
||||
Reference in New Issue
Block a user