diff --git a/config/feature_flags.yaml b/config/feature_flags.yaml index 6bbececa..54e30141 100644 --- a/config/feature_flags.yaml +++ b/config/feature_flags.yaml @@ -73,6 +73,12 @@ mobile: build_modes: [debug, profile, release] description: Mobile WebRTC Remote Desktop view ui_surface: settings_page + logs: + enabled: true + release_tier: stable + build_modes: [debug, profile, release] + description: Mobile runtime logs view + ui_surface: settings_page account_access: enabled: true release_tier: stable @@ -174,6 +180,12 @@ desktop: build_modes: [debug, profile, release] description: Desktop WebRTC Remote Desktop view ui_surface: settings_page + logs: + enabled: true + release_tier: stable + build_modes: [debug, profile, release] + description: Desktop runtime logs view + ui_surface: settings_page account_access: enabled: true release_tier: stable @@ -269,6 +281,12 @@ web: build_modes: [debug, profile, release] description: Web archived task management ui_surface: settings_page + logs: + enabled: true + release_tier: stable + build_modes: [debug, profile, release] + description: Web runtime logs view + ui_surface: settings_page account_access: enabled: true release_tier: stable diff --git a/lib/app/ui_feature_manifest_core.dart b/lib/app/ui_feature_manifest_core.dart index f6f32cf5..80807213 100644 --- a/lib/app/ui_feature_manifest_core.dart +++ b/lib/app/ui_feature_manifest_core.dart @@ -48,6 +48,7 @@ abstract final class UiFeatureKeys { static const settingsGateway = 'settings.gateway'; static const settingsArchivedTasks = 'settings.archived_tasks'; static const settingsRemoteDesktop = 'settings.remote_desktop'; + static const settingsLogs = 'settings.logs'; static const settingsAccountAccess = 'settings.account_access'; static const settingsVaultServer = 'settings.vault_server'; static const settingsExperimentalCanvas = 'settings.experimental_canvas'; @@ -368,6 +369,7 @@ class UiFeatureAccess { UiFeatureKeys.settingsGateway: SettingsTab.gateway, UiFeatureKeys.settingsArchivedTasks: SettingsTab.archivedTasks, UiFeatureKeys.settingsRemoteDesktop: SettingsTab.remoteDesktop, + UiFeatureKeys.settingsLogs: SettingsTab.logs, }; bool isEnabledPath(String path) { diff --git a/lib/features/settings/settings_logs_panel.dart b/lib/features/settings/settings_logs_panel.dart new file mode 100644 index 00000000..986b021f --- /dev/null +++ b/lib/features/settings/settings_logs_panel.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import '../../app/app_controller.dart'; +import '../../i18n/app_language.dart'; +import '../../theme/app_palette.dart'; + +class SettingsLogsPanel extends StatefulWidget { + const SettingsLogsPanel({super.key, required this.controller}); + + final AppController controller; + + @override + State createState() => _SettingsLogsPanelState(); +} + +class _SettingsLogsPanelState extends State { + @override + Widget build(BuildContext context) { + final palette = context.palette; + final theme = Theme.of(context); + + return Column( + key: const ValueKey('settings-logs-panel'), + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Icon(Icons.terminal_outlined, color: palette.textSecondary), + const SizedBox(width: 10), + Expanded( + child: Text( + appText('运行日志', 'Runtime Logs'), + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + Container( + height: 400, + decoration: BoxDecoration( + color: palette.surfaceContainerHighest, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: palette.outlineVariant), + ), + padding: const EdgeInsets.all(16), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.monitor_heart_outlined, size: 48, color: palette.textSecondary.withOpacity(0.5)), + const SizedBox(height: 16), + Text( + appText('暂无日志数据', 'No log data available'), + style: theme.textTheme.bodyMedium?.copyWith( + color: palette.textSecondary, + ), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/lib/features/settings/settings_page_core.dart b/lib/features/settings/settings_page_core.dart index 146c93a5..64bcc759 100644 --- a/lib/features/settings/settings_page_core.dart +++ b/lib/features/settings/settings_page_core.dart @@ -17,6 +17,7 @@ import '../../widgets/surface_card.dart'; import 'settings_account_panel.dart'; import 'settings_about_panel.dart'; import 'settings_archived_tasks_panel.dart'; +import 'settings_logs_panel.dart'; import 'settings_remote_desktop_panel.dart'; Future> loadBridgeMetadataForSettingsAbout({ @@ -529,6 +530,11 @@ class _SettingsPageState extends State { key: const ValueKey('settings-remote-desktop-panel-card'), child: SettingsRemoteDesktopPanel(controller: controller), ), + ] else if (currentTab == SettingsTab.logs) ...[ + SurfaceCard( + key: const ValueKey('settings-logs-panel-card'), + child: SettingsLogsPanel(controller: controller), + ), ], ], ); @@ -564,9 +570,11 @@ class _SettingsTabSelector extends StatelessWidget { icon: Icon( tab == SettingsTab.remoteDesktop ? Icons.desktop_windows_outlined - : (tab == SettingsTab.archivedTasks - ? Icons.inventory_2_outlined - : Icons.hub_outlined), + : (tab == SettingsTab.logs + ? Icons.terminal_outlined + : (tab == SettingsTab.archivedTasks + ? Icons.inventory_2_outlined + : Icons.hub_outlined)), ), label: Text(tab.label), ), diff --git a/lib/models/app_models.dart b/lib/models/app_models.dart index 6160c991..88edc9e7 100644 --- a/lib/models/app_models.dart +++ b/lib/models/app_models.dart @@ -149,13 +149,14 @@ extension AssistantModeCopy on AssistantMode { }; } -enum SettingsTab { gateway, archivedTasks, remoteDesktop } +enum SettingsTab { gateway, archivedTasks, remoteDesktop, logs } extension SettingsTabCopy on SettingsTab { String get label => switch (this) { SettingsTab.gateway => appText('集成', 'Integrations'), SettingsTab.archivedTasks => appText('归档任务', 'Archived tasks'), SettingsTab.remoteDesktop => appText('远程桌面', 'Remote Desktop'), + SettingsTab.logs => appText('运行日志', 'Runtime Logs'), }; }