Add app diagnostic report (#1728)

* feat(diagnostics): add app diagnostic report

* fix(diagnostics): guard app diagnostic runs

* fix(diagnostics): include websocket runtime metrics

* fix(diagnostics): type websocket metric snapshot

* fix(diagnostics): include daemon shell env

* fix(loop): make stop cancellation test deterministic
This commit is contained in:
Mohamed Boudra
2026-06-25 23:20:52 +08:00
committed by GitHub
parent bdd9419189
commit 26f169866f
23 changed files with 1812 additions and 36 deletions
@@ -44,6 +44,7 @@ import {
SquareTerminal,
} from "lucide-react-native";
import { DropdownTrigger } from "@/components/ui/dropdown-trigger";
import { AppDiagnosticSheet } from "@/components/app-diagnostic-sheet";
import { ComboboxTrigger } from "@/components/ui/combobox-trigger";
import { SidebarHeaderRow } from "@/components/sidebar/sidebar-header-row";
import { SidebarSeparator } from "@/components/sidebar/sidebar-separator";
@@ -455,6 +456,8 @@ interface DiagnosticsSectionProps {
isPlaybackTestRunning: boolean;
playbackTestResult: string | null;
handlePlaybackTest: () => Promise<void>;
appVersion: string | null;
isDesktopApp: boolean;
}
function DiagnosticsSection({
@@ -462,14 +465,28 @@ function DiagnosticsSection({
isPlaybackTestRunning,
playbackTestResult,
handlePlaybackTest,
appVersion,
isDesktopApp,
}: DiagnosticsSectionProps) {
const { t } = useTranslation();
const [diagnosticSheetOpen, setDiagnosticSheetOpen] = useState(false);
const handlePlayPress = useCallback(() => {
void handlePlaybackTest();
}, [handlePlaybackTest]);
const handleOpenDiagnostic = useCallback(() => setDiagnosticSheetOpen(true), []);
const handleCloseDiagnostic = useCallback(() => setDiagnosticSheetOpen(false), []);
return (
<SettingsSection title={t("settings.diagnostics.title")}>
<View style={settingsStyles.card}>
<View style={settingsStyles.row} testID="app-diagnostic-row">
<View style={settingsStyles.rowContent}>
<Text style={settingsStyles.rowTitle}>{t("settings.diagnostics.app.rowTitle")}</Text>
<Text style={settingsStyles.rowHint}>{t("settings.diagnostics.app.rowHint")}</Text>
</View>
<Button variant="secondary" size="sm" onPress={handleOpenDiagnostic}>
{t("settings.diagnostics.app.run")}
</Button>
</View>
<View style={settingsStyles.row}>
<View style={settingsStyles.rowContent}>
<Text style={settingsStyles.rowTitle}>{t("settings.diagnostics.testAudio")}</Text>
@@ -489,6 +506,12 @@ function DiagnosticsSection({
</Button>
</View>
</View>
<AppDiagnosticSheet
visible={diagnosticSheetOpen}
onClose={handleCloseDiagnostic}
appVersion={appVersion}
isDesktopApp={isDesktopApp}
/>
</SettingsSection>
);
}
@@ -1533,6 +1556,8 @@ export default function SettingsScreen({ view }: SettingsScreenProps) {
isPlaybackTestRunning={isPlaybackTestRunning}
playbackTestResult={playbackTestResult}
handlePlaybackTest={handlePlaybackTest}
appVersion={appVersion}
isDesktopApp={isDesktopApp}
/>
);
case "about":