From f159541311971b6f67011ba41c544763201b588f Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 3 Dec 2025 18:28:27 +0100 Subject: [PATCH 01/11] feat: hide troubleshoot on prod, Implement auto-off timeout for troubleshoot data recording --- src/libs/actions/Troubleshoot.ts | 25 +++++++++++++++++++ .../Troubleshoot/TroubleshootPage.tsx | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Troubleshoot.ts b/src/libs/actions/Troubleshoot.ts index 8f149d09d132..7d4a0831a4d6 100644 --- a/src/libs/actions/Troubleshoot.ts +++ b/src/libs/actions/Troubleshoot.ts @@ -1,11 +1,36 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; +// Auto-off timeout for troubleshoot recording (10 minutes) +const AUTO_OFF_TIMEOUT_MS = 10 * 60 * 1000; + +// Module-level timeout reference to persist across component mounts/unmounts +let autoOffTimeout: NodeJS.Timeout | null = null; + +/** + * Clear the auto-off timeout if it exists + */ +function clearAutoOffTimeout() { + if (autoOffTimeout) { + clearTimeout(autoOffTimeout); + autoOffTimeout = null; + } +} + /** * Set whether or not to record troubleshoot data * @param shouldRecord Whether or not to record troubleshoot data */ function setShouldRecordTroubleshootData(shouldRecord: boolean) { + clearAutoOffTimeout(); + + if (shouldRecord) { + autoOffTimeout = setTimeout(() => { + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); + autoOffTimeout = null; + }, AUTO_OFF_TIMEOUT_MS); + } + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, shouldRecord); } diff --git a/src/pages/settings/Troubleshoot/TroubleshootPage.tsx b/src/pages/settings/Troubleshoot/TroubleshootPage.tsx index 63ba7a76150e..7f7c4855596c 100644 --- a/src/pages/settings/Troubleshoot/TroubleshootPage.tsx +++ b/src/pages/settings/Troubleshoot/TroubleshootPage.tsx @@ -183,7 +183,7 @@ function TroubleshootPage() { > - + {!isProduction && } Date: Wed, 3 Dec 2025 18:42:06 +0100 Subject: [PATCH 02/11] fix: lint --- src/libs/actions/Troubleshoot.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Troubleshoot.ts b/src/libs/actions/Troubleshoot.ts index 7d4a0831a4d6..a3cc80d63de0 100644 --- a/src/libs/actions/Troubleshoot.ts +++ b/src/libs/actions/Troubleshoot.ts @@ -11,10 +11,12 @@ let autoOffTimeout: NodeJS.Timeout | null = null; * Clear the auto-off timeout if it exists */ function clearAutoOffTimeout() { - if (autoOffTimeout) { - clearTimeout(autoOffTimeout); - autoOffTimeout = null; + if (!autoOffTimeout) { + return; } + + clearTimeout(autoOffTimeout); + autoOffTimeout = null; } /** From 20bc84890ea6ba315fd2b4e8448694f8eebfc675 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 3 Dec 2025 18:57:02 +0100 Subject: [PATCH 03/11] fix: prettier --- src/libs/actions/Troubleshoot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Troubleshoot.ts b/src/libs/actions/Troubleshoot.ts index a3cc80d63de0..b9ac34eb1990 100644 --- a/src/libs/actions/Troubleshoot.ts +++ b/src/libs/actions/Troubleshoot.ts @@ -14,7 +14,7 @@ function clearAutoOffTimeout() { if (!autoOffTimeout) { return; } - + clearTimeout(autoOffTimeout); autoOffTimeout = null; } From 8dacaf6a3dac6217fa77c85fc06ed4421d01aa56 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Thu, 4 Dec 2025 16:17:19 +0100 Subject: [PATCH 04/11] feat: add troubleshoot recording start time and refactor recording management functions --- src/ONYXKEYS.ts | 4 + .../BaseRecordTroubleshootDataToolMenu.tsx | 44 +----- src/libs/actions/Troubleshoot.ts | 146 ++++++++++++++++-- 3 files changed, 148 insertions(+), 46 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index ff5685b0cca2..fa36948acd24 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -441,6 +441,9 @@ const ONYXKEYS = { /** Indicates whether we should record troubleshoot data or not */ SHOULD_RECORD_TROUBLESHOOT_DATA: 'shouldRecordTroubleshootData', + /** Timestamp when troubleshoot recording was started (for auto-off after 10 minutes) */ + TROUBLESHOOT_RECORDING_START_TIME: 'troubleshootRecordingStartTime', + /** Indicates whether we should mask fragile user data while exporting onyx state or not */ SHOULD_MASK_ONYX_STATE: 'shouldMaskOnyxState', @@ -1238,6 +1241,7 @@ type OnyxValuesMapping = { [ONYXKEYS.LOGS]: OnyxTypes.CapturedLogs; [ONYXKEYS.SHOULD_STORE_LOGS]: boolean; [ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA]: boolean; + [ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME]: number; [ONYXKEYS.SHOULD_MASK_ONYX_STATE]: boolean; [ONYXKEYS.SHOULD_USE_STAGING_SERVER]: boolean; [ONYXKEYS.IS_DEBUG_MODE_ENABLED]: boolean; diff --git a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx index 057060dc12c4..6e05b6c1fece 100644 --- a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx +++ b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx @@ -4,7 +4,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {Alert} from 'react-native'; import RNFetchBlob from 'react-native-blob-util'; import DeviceInfo from 'react-native-device-info'; -import {startProfiling, stopProfiling} from 'react-native-release-profiler'; +import {stopProfiling} from 'react-native-release-profiler'; import Button from '@components/Button'; import Switch from '@components/Switch'; import TestToolRow from '@components/TestToolRow'; @@ -12,9 +12,7 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; -import {disableLoggingAndFlushLogs, setShouldStoreLogs} from '@libs/actions/Console'; -import toggleProfileTool from '@libs/actions/ProfilingTool'; -import {setShouldRecordTroubleshootData} from '@libs/actions/Troubleshoot'; +import {disableRecording, enableRecording} from '@libs/actions/Troubleshoot'; import {parseStringifiedMessages} from '@libs/Console'; import getPlatform from '@libs/getPlatform'; import Log from '@libs/Log'; @@ -88,29 +86,12 @@ function BaseRecordTroubleshootDataToolMenu({ const styles = useThemeStyles(); const [shouldRecordTroubleshootData] = useOnyx(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, {canBeMissing: true}); const [capturedLogs] = useOnyx(ONYXKEYS.LOGS, {canBeMissing: true}); - const [isProfilingInProgress] = useOnyx(ONYXKEYS.APP_PROFILING_IN_PROGRESS, {canBeMissing: true}); const [shareUrls, setShareUrls] = useState(); const [isDisabled, setIsDisabled] = useState(false); const [profileTracePath, setProfileTracePath] = useState(); const shouldShowProfileTool = useMemo(() => shouldShowProfileToolUtil(), []); - const onToggleProfiling = useCallback(() => { - const shouldProfiling = !isProfilingInProgress; - if (shouldProfiling) { - setShareUrls(undefined); - Memoize.startMonitoring(); - Performance.enableMonitoring(); - startProfiling(); - } else { - Performance.disableMonitoring(); - } - toggleProfileTool(shouldProfiling); - return () => { - Performance.disableMonitoring(); - }; - }, [isProfilingInProgress]); - const getAppInfo = useCallback(() => { return Promise.all([DeviceInfo.getTotalMemory(), DeviceInfo.getUsedMemory()]).then(([totalMemory, usedMemory]) => { return JSON.stringify({ @@ -128,12 +109,8 @@ function BaseRecordTroubleshootDataToolMenu({ const onStopProfiling = useMemo(() => (shouldShowProfileTool ? stopProfiling : () => Promise.resolve()), [shouldShowProfileTool]); const onToggle = () => { - if (shouldShowProfileTool) { - onToggleProfiling(); - } if (!shouldRecordTroubleshootData) { - setShouldStoreLogs(true); - setShouldRecordTroubleshootData(true); + enableRecording(); if (onEnableLogging) { onEnableLogging(); @@ -146,8 +123,7 @@ function BaseRecordTroubleshootDataToolMenu({ if (!capturedLogs) { Alert.alert(translate('initialSettingsPage.troubleshoot.noLogsToShare')); - disableLoggingAndFlushLogs(); - setShouldRecordTroubleshootData(false); + disableRecording(); return; } @@ -162,8 +138,7 @@ function BaseRecordTroubleshootDataToolMenu({ zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableLoggingAndFlushLogs(); - setShouldRecordTroubleshootData(false); + disableRecording(); setIsDisabled(false); onDownloadZip?.(); }); @@ -198,8 +173,7 @@ function BaseRecordTroubleshootDataToolMenu({ zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableLoggingAndFlushLogs(); - setShouldRecordTroubleshootData(false); + disableRecording(); setIsDisabled(false); onDownloadZip?.(); }); @@ -233,8 +207,7 @@ function BaseRecordTroubleshootDataToolMenu({ zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableLoggingAndFlushLogs(); - setShouldRecordTroubleshootData(false); + disableRecording(); setIsDisabled(false); }); }); @@ -246,8 +219,7 @@ function BaseRecordTroubleshootDataToolMenu({ zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableLoggingAndFlushLogs(); - setShouldRecordTroubleshootData(false); + disableRecording(); setIsDisabled(false); }); }); diff --git a/src/libs/actions/Troubleshoot.ts b/src/libs/actions/Troubleshoot.ts index b9ac34eb1990..df53ae815678 100644 --- a/src/libs/actions/Troubleshoot.ts +++ b/src/libs/actions/Troubleshoot.ts @@ -1,11 +1,22 @@ -import Onyx from 'react-native-onyx'; +import Onyx, {OnyxEntry} from 'react-native-onyx'; +import {startProfiling} from 'react-native-release-profiler'; +import {Memoize} from '@libs/memoize'; +import Performance from '@libs/Performance'; import ONYXKEYS from '@src/ONYXKEYS'; +import {disableLoggingAndFlushLogs, setShouldStoreLogs} from './Console'; +import toggleProfileTool from './ProfilingTool'; +import {shouldShowProfileTool} from './TestTool'; // Auto-off timeout for troubleshoot recording (10 minutes) const AUTO_OFF_TIMEOUT_MS = 10 * 60 * 1000; -// Module-level timeout reference to persist across component mounts/unmounts +// Module-level state let autoOffTimeout: NodeJS.Timeout | null = null; +let shouldRecordTroubleshootData: OnyxEntry; +let troubleshootRecordingStartTime: OnyxEntry; +let isRecordingLoaded = false; +let isStartTimeLoaded = false; +let isInitialized = false; /** * Clear the auto-off timeout if it exists @@ -19,6 +30,122 @@ function clearAutoOffTimeout() { autoOffTimeout = null; } +/** + * Disable troubleshoot recording, stop profiling, and clean up logs. + * Used for auto-off and invalid state cleanup. + */ +function disableRecording() { + clearAutoOffTimeout(); + + // Stop profiling and performance monitoring + Performance.disableMonitoring(); + Memoize.stopMonitoring(); + toggleProfileTool(false); + + // Disable logging and flush logs + disableLoggingAndFlushLogs(); + + // Update Onyx state + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); + Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); +} + +/** + * Schedule auto-off after the given time + */ +function scheduleAutoOff(remainingTime: number) { + clearAutoOffTimeout(); + autoOffTimeout = setTimeout(() => { + disableRecording(); + autoOffTimeout = null; + }, remainingTime); +} + +/** + * Enable troubleshoot recording, start profiling, and enable log storage. + */ +function enableRecording() { + clearAutoOffTimeout(); + + // Enable log storage + setShouldStoreLogs(true); + + // Start profiling and performance monitoring if available + if (shouldShowProfileTool()) { + Memoize.startMonitoring(); + Performance.enableMonitoring(); + startProfiling(); + toggleProfileTool(true); + } + + // Update Onyx state and schedule auto-off + Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, Date.now()); + scheduleAutoOff(AUTO_OFF_TIMEOUT_MS); + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, true); +} + +/** + * Check recording state on app load and handle accordingly. + * - If recording ON but no start time → disable (invalid state) + * - If recording ON and start time exists → calculate remaining time or disable if exceeded + */ +function tryInitialize() { + if (isInitialized || !isRecordingLoaded || !isStartTimeLoaded) { + return; + } + isInitialized = true; + + if (!shouldRecordTroubleshootData) { + return; + } + + // Recording is ON but no start time - invalid state, disable + if (!troubleshootRecordingStartTime) { + disableRecording(); + return; + } + + // Calculate remaining time + const elapsedTime = Date.now() - troubleshootRecordingStartTime; + + if (elapsedTime >= AUTO_OFF_TIMEOUT_MS) { + // Time exceeded, disable recording + disableRecording(); + } else { + // Schedule auto-off for remaining time + const remainingTime = AUTO_OFF_TIMEOUT_MS - elapsedTime; + scheduleAutoOff(remainingTime); + } +} + +/** + * Listen for changes to the troubleshoot recording flag. + * On app load, triggers initialization to handle auto-off timer. + */ +Onyx.connect({ + key: ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, + initWithStoredValues: true, + callback: (value) => { + shouldRecordTroubleshootData = value; + isRecordingLoaded = true; + tryInitialize(); + }, +}); + +/** + * Listen for changes to the recording start time. + * On app load, triggers initialization to calculate remaining time for auto-off. + */ +Onyx.connect({ + key: ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, + initWithStoredValues: true, + callback: (value) => { + troubleshootRecordingStartTime = value; + isStartTimeLoaded = true; + tryInitialize(); + }, +}); + /** * Set whether or not to record troubleshoot data * @param shouldRecord Whether or not to record troubleshoot data @@ -27,14 +154,13 @@ function setShouldRecordTroubleshootData(shouldRecord: boolean) { clearAutoOffTimeout(); if (shouldRecord) { - autoOffTimeout = setTimeout(() => { - Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); - autoOffTimeout = null; - }, AUTO_OFF_TIMEOUT_MS); + Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, Date.now()); + scheduleAutoOff(AUTO_OFF_TIMEOUT_MS); + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, true); + } else { + Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); } - - Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, shouldRecord); } -// eslint-disable-next-line import/prefer-default-export -export {setShouldRecordTroubleshootData}; +export {setShouldRecordTroubleshootData, enableRecording, disableRecording}; From 75b6559084d2fc31f47e49c72a5e0e2e3412f076 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Thu, 4 Dec 2025 16:39:08 +0100 Subject: [PATCH 05/11] refactor: centralize profiling data handling and cleanup in Troubleshoot actions --- .../BaseRecordTroubleshootDataToolMenu.tsx | 72 ++++++++----------- src/libs/actions/Troubleshoot.ts | 48 ++++++++++++- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx index 6e05b6c1fece..bb7b7e6bac79 100644 --- a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx +++ b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx @@ -1,10 +1,9 @@ import type JSZip from 'jszip'; import type {RefObject} from 'react'; -import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useEffect, useState} from 'react'; import {Alert} from 'react-native'; import RNFetchBlob from 'react-native-blob-util'; import DeviceInfo from 'react-native-device-info'; -import {stopProfiling} from 'react-native-release-profiler'; import Button from '@components/Button'; import Switch from '@components/Switch'; import TestToolRow from '@components/TestToolRow'; @@ -12,13 +11,11 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; -import {disableRecording, enableRecording} from '@libs/actions/Troubleshoot'; +import {cleanupAfterDisable, disableRecording, enableRecording, stopProfilingAndGetData} from '@libs/actions/Troubleshoot'; +import type {ProfilingData} from '@libs/actions/Troubleshoot'; import {parseStringifiedMessages} from '@libs/Console'; import getPlatform from '@libs/getPlatform'; import Log from '@libs/Log'; -import {Memoize} from '@libs/memoize'; -import Performance from '@libs/Performance'; -import {shouldShowProfileTool as shouldShowProfileToolUtil} from '@userActions/TestTool'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -90,9 +87,7 @@ function BaseRecordTroubleshootDataToolMenu({ const [isDisabled, setIsDisabled] = useState(false); const [profileTracePath, setProfileTracePath] = useState(); - const shouldShowProfileTool = useMemo(() => shouldShowProfileToolUtil(), []); - - const getAppInfo = useCallback(() => { + const getAppInfo = useCallback((profilingData: ProfilingData) => { return Promise.all([DeviceInfo.getTotalMemory(), DeviceInfo.getUsedMemory()]).then(([totalMemory, usedMemory]) => { return JSON.stringify({ appVersion: pkg.version, @@ -100,13 +95,11 @@ function BaseRecordTroubleshootDataToolMenu({ platform: getPlatform(), totalMemory: formatBytes(totalMemory, 2), usedMemory: formatBytes(usedMemory, 2), - memoizeStats: Memoize.stopMonitoring(), - performance: shouldShowProfileTool ? Performance.getPerformanceMeasures() : undefined, + memoizeStats: profilingData.memoizeStats, + performance: profilingData.performanceMeasures, }); }); - }, [shouldShowProfileTool]); - - const onStopProfiling = useMemo(() => (shouldShowProfileTool ? stopProfiling : () => Promise.resolve()), [shouldShowProfileTool]); + }, []); const onToggle = () => { if (!shouldRecordTroubleshootData) { @@ -132,21 +125,22 @@ function BaseRecordTroubleshootDataToolMenu({ const infoFileName = `App_Info_${pkg.version}.json`; - if (getPlatform() === CONST.PLATFORM.WEB) { - onStopProfiling(true, newFileName).then(() => { - getAppInfo().then((appInfo) => { + // Stop profiling and get data (centralized in Troubleshoot.ts) + stopProfilingAndGetData(newFileName).then((profilingData) => { + const {profilePath} = profilingData; + + if (getPlatform() === CONST.PLATFORM.WEB) { + getAppInfo(profilingData).then((appInfo) => { zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableRecording(); + cleanupAfterDisable(); setIsDisabled(false); onDownloadZip?.(); }); }); - }); - } else if (getPlatform() === CONST.PLATFORM.IOS) { - onStopProfiling(true, newFileName).then((path) => { - if (!path) { + } else if (getPlatform() === CONST.PLATFORM.IOS) { + if (!profilePath) { return; } @@ -167,13 +161,13 @@ function BaseRecordTroubleshootDataToolMenu({ Log.hmmm('[ProfilingToolMenu] error checking/deleting existing file: ', typedError.message); }) .then(() => { - RNFS.copyFile(path, newFilePath) + RNFS.copyFile(profilePath, newFilePath) .then(() => { - getAppInfo().then((appInfo) => { + getAppInfo(profilingData).then((appInfo) => { zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableRecording(); + cleanupAfterDisable(); setIsDisabled(false); onDownloadZip?.(); }); @@ -190,41 +184,37 @@ function BaseRecordTroubleshootDataToolMenu({ console.error('[ProfilingToolMenu] error copying file: ', error); Log.hmmm('[ProfilingToolMenu] error copying file: ', error); }); - }); - } else if (getPlatform() === CONST.PLATFORM.ANDROID) { - onStopProfiling(true, newFileName).then((path) => { - if (!path) { + } else if (getPlatform() === CONST.PLATFORM.ANDROID) { + if (!profilePath) { return; } RNFetchBlob.fs // Check if it is an internal path of `DownloadManager` then append content://media to create a valid url - .stat(!path.startsWith('content://media/') && path.match(/\/downloads\/\d+$/) ? `content://media/${path}` : path) + .stat(!profilePath.startsWith('content://media/') && profilePath.match(/\/downloads\/\d+$/) ? `content://media/${profilePath}` : profilePath) .then(({path: realPath}) => setProfileTracePath(realPath)) - .catch(() => setProfileTracePath(path)); + .catch(() => setProfileTracePath(profilePath)); - getAppInfo().then((appInfo) => { + getAppInfo(profilingData).then((appInfo) => { zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableRecording(); + cleanupAfterDisable(); setIsDisabled(false); }); }); - }); - } else { - // Desktop - onStopProfiling(true, newFileName).then(() => { - getAppInfo().then((appInfo) => { + } else { + // Desktop + getAppInfo(profilingData).then((appInfo) => { zipRef.current?.file(infoFileName, appInfo); onDisableLogging(logsWithParsedMessages).then(() => { - disableRecording(); + cleanupAfterDisable(); setIsDisabled(false); }); }); - }); - } + } + }); }; useEffect(() => { diff --git a/src/libs/actions/Troubleshoot.ts b/src/libs/actions/Troubleshoot.ts index df53ae815678..50ebbbe24212 100644 --- a/src/libs/actions/Troubleshoot.ts +++ b/src/libs/actions/Troubleshoot.ts @@ -1,5 +1,6 @@ -import Onyx, {OnyxEntry} from 'react-native-onyx'; -import {startProfiling} from 'react-native-release-profiler'; +import Onyx from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import {startProfiling, stopProfiling} from 'react-native-release-profiler'; import {Memoize} from '@libs/memoize'; import Performance from '@libs/Performance'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -7,6 +8,12 @@ import {disableLoggingAndFlushLogs, setShouldStoreLogs} from './Console'; import toggleProfileTool from './ProfilingTool'; import {shouldShowProfileTool} from './TestTool'; +type ProfilingData = { + profilePath: string | undefined; + memoizeStats: ReturnType; + performanceMeasures: ReturnType | undefined; +}; + // Auto-off timeout for troubleshoot recording (10 minutes) const AUTO_OFF_TIMEOUT_MS = 10 * 60 * 1000; @@ -30,6 +37,29 @@ function clearAutoOffTimeout() { autoOffTimeout = null; } +/** + * Stop profiling and get profiling data. + * Used for manual disable to get profile path and stats before cleanup. + * @param fileName - The filename to save the profile trace as + * @returns Profile path, memoize stats, and performance measures + */ +async function stopProfilingAndGetData(fileName: string): Promise { + const showProfileTool = shouldShowProfileTool(); + + // Stop profiler and save to file (only if profiling is available) + const profilePath = showProfileTool ? await stopProfiling(true, fileName) : undefined; + + // Get stats before stopping monitoring + const memoizeStats = Memoize.stopMonitoring(); + const performanceMeasures = showProfileTool ? Performance.getPerformanceMeasures() : undefined; + + // Stop monitoring + Performance.disableMonitoring(); + toggleProfileTool(false); + + return {profilePath, memoizeStats, performanceMeasures}; +} + /** * Disable troubleshoot recording, stop profiling, and clean up logs. * Used for auto-off and invalid state cleanup. @@ -50,6 +80,17 @@ function disableRecording() { Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); } +/** + * Clean up Onyx state and flush logs. + * Used after manual disable when profiling was already stopped via stopProfilingAndGetData. + */ +function cleanupAfterDisable() { + clearAutoOffTimeout(); + disableLoggingAndFlushLogs(); + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); + Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); +} + /** * Schedule auto-off after the given time */ @@ -163,4 +204,5 @@ function setShouldRecordTroubleshootData(shouldRecord: boolean) { } } -export {setShouldRecordTroubleshootData, enableRecording, disableRecording}; +export {setShouldRecordTroubleshootData, enableRecording, disableRecording, stopProfilingAndGetData, cleanupAfterDisable}; +export type {ProfilingData}; From 0d770615a9a8029abcbdf912557fb69980018731 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 10 Dec 2025 20:14:36 +0100 Subject: [PATCH 06/11] fix comments --- src/ONYXKEYS.ts | 2 +- .../BaseRecordTroubleshootDataToolMenu.tsx | 113 ++++-------------- .../handleStopRecording.android.ts | 31 +++++ .../handleStopRecording.ios.ts | 57 +++++++++ .../handleStopRecording.native.ts | 18 +++ .../handleStopRecording.types.ts | 20 ++++ .../handleStopRecording.web.ts | 18 +++ src/libs/actions/Troubleshoot.ts | 44 +++---- 8 files changed, 190 insertions(+), 113 deletions(-) create mode 100644 src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts create mode 100644 src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts create mode 100644 src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts create mode 100644 src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts create mode 100644 src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 4e7378eb774f..a8dbfd1348d4 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1247,7 +1247,7 @@ type OnyxValuesMapping = { [ONYXKEYS.LOGS]: OnyxTypes.CapturedLogs; [ONYXKEYS.SHOULD_STORE_LOGS]: boolean; [ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA]: boolean; - [ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME]: number; + [ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME]: number | null; [ONYXKEYS.SHOULD_MASK_ONYX_STATE]: boolean; [ONYXKEYS.SHOULD_USE_STAGING_SERVER]: boolean; [ONYXKEYS.IS_DEBUG_MODE_ENABLED]: boolean; diff --git a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx index bb7b7e6bac79..7e08e003f7aa 100644 --- a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx +++ b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx @@ -2,7 +2,6 @@ import type JSZip from 'jszip'; import type {RefObject} from 'react'; import React, {useCallback, useEffect, useState} from 'react'; import {Alert} from 'react-native'; -import RNFetchBlob from 'react-native-blob-util'; import DeviceInfo from 'react-native-device-info'; import Button from '@components/Button'; import Switch from '@components/Switch'; @@ -15,14 +14,13 @@ import {cleanupAfterDisable, disableRecording, enableRecording, stopProfilingAnd import type {ProfilingData} from '@libs/actions/Troubleshoot'; import {parseStringifiedMessages} from '@libs/Console'; import getPlatform from '@libs/getPlatform'; -import Log from '@libs/Log'; import CONFIG from '@src/CONFIG'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Log as OnyxLog} from '@src/types/onyx'; -import pkg from '../../../package.json'; -import RNFS from './RNFS'; +import handleStopRecording from './handleStopRecording'; +import type {StopRecordingParams} from './handleStopRecording.types'; import Share from './Share'; +import pkg from '../../../package.json'; type File = { path: string; @@ -125,95 +123,26 @@ function BaseRecordTroubleshootDataToolMenu({ const infoFileName = `App_Info_${pkg.version}.json`; - // Stop profiling and get data (centralized in Troubleshoot.ts) stopProfilingAndGetData(newFileName).then((profilingData) => { - const {profilePath} = profilingData; - - if (getPlatform() === CONST.PLATFORM.WEB) { - getAppInfo(profilingData).then((appInfo) => { - zipRef.current?.file(infoFileName, appInfo); - - onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - setIsDisabled(false); - onDownloadZip?.(); - }); + getAppInfo(profilingData).then((appInfo) => { + const params: StopRecordingParams = { + profilingData, + infoFileName, + profileFileName: newFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + pathToBeUsed, + onDownloadZip, + setProfileTracePath, + }; + + handleStopRecording(params).finally(() => { + setIsDisabled(false); }); - } else if (getPlatform() === CONST.PLATFORM.IOS) { - if (!profilePath) { - return; - } - - const newFilePath = `${pathToBeUsed}/${newFileName}`; - - RNFS.exists(newFilePath) - .then((fileExists) => { - if (!fileExists) { - return; - } - - return RNFS.unlink(newFilePath).then(() => { - Log.hmmm('[ProfilingToolMenu] existing file deleted successfully'); - }); - }) - .catch((error) => { - const typedError = error as Error; - Log.hmmm('[ProfilingToolMenu] error checking/deleting existing file: ', typedError.message); - }) - .then(() => { - RNFS.copyFile(profilePath, newFilePath) - .then(() => { - getAppInfo(profilingData).then((appInfo) => { - zipRef.current?.file(infoFileName, appInfo); - - onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - setIsDisabled(false); - onDownloadZip?.(); - }); - }); - Log.hmmm('[ProfilingToolMenu] file copied successfully'); - - setProfileTracePath(newFilePath); - }) - .catch((err) => { - console.error('[ProfilingToolMenu] error copying file: ', err); - }); - }) - .catch((error: Record) => { - console.error('[ProfilingToolMenu] error copying file: ', error); - Log.hmmm('[ProfilingToolMenu] error copying file: ', error); - }); - } else if (getPlatform() === CONST.PLATFORM.ANDROID) { - if (!profilePath) { - return; - } - - RNFetchBlob.fs - // Check if it is an internal path of `DownloadManager` then append content://media to create a valid url - .stat(!profilePath.startsWith('content://media/') && profilePath.match(/\/downloads\/\d+$/) ? `content://media/${profilePath}` : profilePath) - .then(({path: realPath}) => setProfileTracePath(realPath)) - .catch(() => setProfileTracePath(profilePath)); - - getAppInfo(profilingData).then((appInfo) => { - zipRef.current?.file(infoFileName, appInfo); - - onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - setIsDisabled(false); - }); - }); - } else { - // Desktop - getAppInfo(profilingData).then((appInfo) => { - zipRef.current?.file(infoFileName, appInfo); - - onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - setIsDisabled(false); - }); - }); - } + }); }); }; diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts new file mode 100644 index 000000000000..904e0c10a476 --- /dev/null +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts @@ -0,0 +1,31 @@ +import RNFetchBlob from 'react-native-blob-util'; +import type {StopRecordingParams} from './handleStopRecording.types'; + +export default function handleStopRecording({ + profilingData, + infoFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + onDownloadZip, + setProfileTracePath, +}: StopRecordingParams): Promise { + const {profilePath} = profilingData; + + if (profilePath) { + RNFetchBlob.fs + // Check if it is an internal path of `DownloadManager` then append content://media to create a valid url + .stat(!profilePath.startsWith('content://media/') && profilePath.match(/\/downloads\/\d+$/) ? `content://media/${profilePath}` : profilePath) + .then(({path}) => setProfileTracePath?.(path)) + .catch(() => setProfileTracePath?.(profilePath)); + } + + zipRef.current?.file(infoFileName, appInfo); + + return onDisableLogging(logsWithParsedMessages).then(() => { + cleanupAfterDisable(); + onDownloadZip?.(); + }); +} diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts new file mode 100644 index 000000000000..52b33ec0601d --- /dev/null +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts @@ -0,0 +1,57 @@ +import RNFS from 'react-native-fs'; +import Log from '@libs/Log'; +import type {StopRecordingParams} from './handleStopRecording.types'; + +export default function handleStopRecording({ + profilingData, + infoFileName, + profileFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + pathToBeUsed, + onDownloadZip, + setProfileTracePath, +}: StopRecordingParams): Promise { + const {profilePath} = profilingData; + + if (!profilePath) { + cleanupAfterDisable(); + return Promise.resolve(); + } + + const newFilePath = `${pathToBeUsed}/${profileFileName}`; + + return RNFS.exists(newFilePath) + .then((fileExists) => { + if (!fileExists) { + return; + } + + return RNFS.unlink(newFilePath).then(() => { + Log.hmmm('[ProfilingToolMenu] existing file deleted successfully'); + }); + }) + .catch((error) => { + const typedError = error as Error; + Log.hmmm('[ProfilingToolMenu] error checking/deleting existing file: ', typedError.message); + }) + .then(() => RNFS.copyFile(profilePath, newFilePath)) + .then(() => { + zipRef.current?.file(infoFileName, appInfo); + + return onDisableLogging(logsWithParsedMessages).then(() => { + cleanupAfterDisable(); + onDownloadZip?.(); + }); + }) + .then(() => { + setProfileTracePath?.(newFilePath); + Log.hmmm('[ProfilingToolMenu] file copied successfully'); + }) + .catch((error) => { + Log.hmmm('[ProfilingToolMenu] error copying file: ', error); + }); +} diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts new file mode 100644 index 000000000000..04f58a4b8c08 --- /dev/null +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts @@ -0,0 +1,18 @@ +import type {StopRecordingParams} from './handleStopRecording.types'; + +export default function handleStopRecording({ + infoFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + onDownloadZip, +}: StopRecordingParams): Promise { + zipRef.current?.file(infoFileName, appInfo); + + return onDisableLogging(logsWithParsedMessages).then(() => { + cleanupAfterDisable(); + onDownloadZip?.(); + }); +} diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts new file mode 100644 index 000000000000..e199aa3dbb9b --- /dev/null +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts @@ -0,0 +1,20 @@ +import type JSZip from 'jszip'; +import type {RefObject} from 'react'; +import type {ProfilingData} from '@libs/actions/Troubleshoot'; +import type {Log as OnyxLog} from '@src/types/onyx'; + +type StopRecordingParams = { + profilingData: ProfilingData; + infoFileName: string; + profileFileName: string; + appInfo: string; + logsWithParsedMessages: OnyxLog[]; + onDisableLogging: (logs: OnyxLog[]) => Promise; + cleanupAfterDisable: () => void; + zipRef: RefObject>; + pathToBeUsed: string; + onDownloadZip?: () => void; + setProfileTracePath?: (path: string) => void; +}; + +export type {StopRecordingParams}; diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts new file mode 100644 index 000000000000..04f58a4b8c08 --- /dev/null +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts @@ -0,0 +1,18 @@ +import type {StopRecordingParams} from './handleStopRecording.types'; + +export default function handleStopRecording({ + infoFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + onDownloadZip, +}: StopRecordingParams): Promise { + zipRef.current?.file(infoFileName, appInfo); + + return onDisableLogging(logsWithParsedMessages).then(() => { + cleanupAfterDisable(); + onDownloadZip?.(); + }); +} diff --git a/src/libs/actions/Troubleshoot.ts b/src/libs/actions/Troubleshoot.ts index 50ebbbe24212..3ca4c72d9521 100644 --- a/src/libs/actions/Troubleshoot.ts +++ b/src/libs/actions/Troubleshoot.ts @@ -9,9 +9,9 @@ import toggleProfileTool from './ProfilingTool'; import {shouldShowProfileTool} from './TestTool'; type ProfilingData = { - profilePath: string | undefined; + profilePath?: string; memoizeStats: ReturnType; - performanceMeasures: ReturnType | undefined; + performanceMeasures?: ReturnType; }; // Auto-off timeout for troubleshoot recording (10 minutes) @@ -20,7 +20,7 @@ const AUTO_OFF_TIMEOUT_MS = 10 * 60 * 1000; // Module-level state let autoOffTimeout: NodeJS.Timeout | null = null; let shouldRecordTroubleshootData: OnyxEntry; -let troubleshootRecordingStartTime: OnyxEntry; +let troubleshootRecordingStartTime: OnyxEntry; let isRecordingLoaded = false; let isStartTimeLoaded = false; let isInitialized = false; @@ -43,27 +43,34 @@ function clearAutoOffTimeout() { * @param fileName - The filename to save the profile trace as * @returns Profile path, memoize stats, and performance measures */ -async function stopProfilingAndGetData(fileName: string): Promise { +function stopProfilingAndGetData(fileName: string): Promise { const showProfileTool = shouldShowProfileTool(); // Stop profiler and save to file (only if profiling is available) - const profilePath = showProfileTool ? await stopProfiling(true, fileName) : undefined; + const profilingPromise = showProfileTool ? stopProfiling(true, fileName) : Promise.resolve(undefined); - // Get stats before stopping monitoring - const memoizeStats = Memoize.stopMonitoring(); - const performanceMeasures = showProfileTool ? Performance.getPerformanceMeasures() : undefined; + return profilingPromise.then((profilePath) => { + // Get stats before stopping monitoring + const memoizeStats = Memoize.stopMonitoring(); + const performanceMeasures = showProfileTool ? Performance.getPerformanceMeasures() : undefined; - // Stop monitoring - Performance.disableMonitoring(); - toggleProfileTool(false); + // Stop monitoring + Performance.disableMonitoring(); + toggleProfileTool(false); - return {profilePath, memoizeStats, performanceMeasures}; + return {profilePath, memoizeStats, performanceMeasures}; + }); } /** * Disable troubleshoot recording, stop profiling, and clean up logs. * Used for auto-off and invalid state cleanup. */ +function clearRecordingOnyxState() { + Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); + Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); +} + function disableRecording() { clearAutoOffTimeout(); @@ -76,8 +83,7 @@ function disableRecording() { disableLoggingAndFlushLogs(); // Update Onyx state - Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); - Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); + clearRecordingOnyxState(); } /** @@ -87,8 +93,7 @@ function disableRecording() { function cleanupAfterDisable() { clearAutoOffTimeout(); disableLoggingAndFlushLogs(); - Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); - Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); + clearRecordingOnyxState(); } /** @@ -163,7 +168,7 @@ function tryInitialize() { * Listen for changes to the troubleshoot recording flag. * On app load, triggers initialization to handle auto-off timer. */ -Onyx.connect({ +Onyx.connectWithoutView({ key: ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, initWithStoredValues: true, callback: (value) => { @@ -177,7 +182,7 @@ Onyx.connect({ * Listen for changes to the recording start time. * On app load, triggers initialization to calculate remaining time for auto-off. */ -Onyx.connect({ +Onyx.connectWithoutView({ key: ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, initWithStoredValues: true, callback: (value) => { @@ -199,8 +204,7 @@ function setShouldRecordTroubleshootData(shouldRecord: boolean) { scheduleAutoOff(AUTO_OFF_TIMEOUT_MS); Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, true); } else { - Onyx.set(ONYXKEYS.TROUBLESHOOT_RECORDING_START_TIME, null); - Onyx.set(ONYXKEYS.SHOULD_RECORD_TROUBLESHOOT_DATA, false); + clearRecordingOnyxState(); } } From 751337ec21e2e6293e5f5df84afe7b4beedd9c21 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 10 Dec 2025 20:28:51 +0100 Subject: [PATCH 07/11] Refactor handleStopRecording functions to use async/await for improved readability and error handling --- .../BaseRecordTroubleshootDataToolMenu.tsx | 66 +++++++++---------- .../handleStopRecording.android.ts | 21 +++--- .../handleStopRecording.ios.ts | 54 +++++++-------- .../handleStopRecording.native.ts | 9 ++- .../handleStopRecording.web.ts | 9 ++- src/libs/actions/Troubleshoot.ts | 20 +++--- 6 files changed, 86 insertions(+), 93 deletions(-) diff --git a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx index 7e08e003f7aa..3b54fde1927f 100644 --- a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx +++ b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx @@ -85,21 +85,20 @@ function BaseRecordTroubleshootDataToolMenu({ const [isDisabled, setIsDisabled] = useState(false); const [profileTracePath, setProfileTracePath] = useState(); - const getAppInfo = useCallback((profilingData: ProfilingData) => { - return Promise.all([DeviceInfo.getTotalMemory(), DeviceInfo.getUsedMemory()]).then(([totalMemory, usedMemory]) => { - return JSON.stringify({ - appVersion: pkg.version, - environment: CONFIG.ENVIRONMENT, - platform: getPlatform(), - totalMemory: formatBytes(totalMemory, 2), - usedMemory: formatBytes(usedMemory, 2), - memoizeStats: profilingData.memoizeStats, - performance: profilingData.performanceMeasures, - }); + const getAppInfo = useCallback(async (profilingData: ProfilingData) => { + const [totalMemory, usedMemory] = await Promise.all([DeviceInfo.getTotalMemory(), DeviceInfo.getUsedMemory()]); + return JSON.stringify({ + appVersion: pkg.version, + environment: CONFIG.ENVIRONMENT, + platform: getPlatform(), + totalMemory: formatBytes(totalMemory, 2), + usedMemory: formatBytes(usedMemory, 2), + memoizeStats: profilingData.memoizeStats, + performance: profilingData.performanceMeasures, }); }, []); - const onToggle = () => { + const onToggle = async () => { if (!shouldRecordTroubleshootData) { enableRecording(); @@ -123,27 +122,28 @@ function BaseRecordTroubleshootDataToolMenu({ const infoFileName = `App_Info_${pkg.version}.json`; - stopProfilingAndGetData(newFileName).then((profilingData) => { - getAppInfo(profilingData).then((appInfo) => { - const params: StopRecordingParams = { - profilingData, - infoFileName, - profileFileName: newFileName, - appInfo, - logsWithParsedMessages, - onDisableLogging, - cleanupAfterDisable, - zipRef, - pathToBeUsed, - onDownloadZip, - setProfileTracePath, - }; - - handleStopRecording(params).finally(() => { - setIsDisabled(false); - }); - }); - }); + try { + const profilingData = await stopProfilingAndGetData(newFileName); + const appInfo = await getAppInfo(profilingData); + + const params: StopRecordingParams = { + profilingData, + infoFileName, + profileFileName: newFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + pathToBeUsed, + onDownloadZip, + setProfileTracePath, + }; + + await handleStopRecording(params); + } finally { + setIsDisabled(false); + } }; useEffect(() => { diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts index 904e0c10a476..5b50fa52bcc8 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts @@ -1,7 +1,7 @@ import RNFetchBlob from 'react-native-blob-util'; import type {StopRecordingParams} from './handleStopRecording.types'; -export default function handleStopRecording({ +export default async function handleStopRecording({ profilingData, infoFileName, appInfo, @@ -15,17 +15,20 @@ export default function handleStopRecording({ const {profilePath} = profilingData; if (profilePath) { - RNFetchBlob.fs + try { // Check if it is an internal path of `DownloadManager` then append content://media to create a valid url - .stat(!profilePath.startsWith('content://media/') && profilePath.match(/\/downloads\/\d+$/) ? `content://media/${profilePath}` : profilePath) - .then(({path}) => setProfileTracePath?.(path)) - .catch(() => setProfileTracePath?.(profilePath)); + const {path} = await RNFetchBlob.fs.stat( + !profilePath.startsWith('content://media/') && profilePath.match(/\/downloads\/\d+$/) ? `content://media/${profilePath}` : profilePath, + ); + setProfileTracePath?.(path); + } catch { + setProfileTracePath?.(profilePath); + } } zipRef.current?.file(infoFileName, appInfo); - return onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - onDownloadZip?.(); - }); + await onDisableLogging(logsWithParsedMessages); + cleanupAfterDisable(); + onDownloadZip?.(); } diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts index 52b33ec0601d..d14ff4b57e5e 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts @@ -2,7 +2,7 @@ import RNFS from 'react-native-fs'; import Log from '@libs/Log'; import type {StopRecordingParams} from './handleStopRecording.types'; -export default function handleStopRecording({ +export default async function handleStopRecording({ profilingData, infoFileName, profileFileName, @@ -19,39 +19,33 @@ export default function handleStopRecording({ if (!profilePath) { cleanupAfterDisable(); - return Promise.resolve(); + return; } const newFilePath = `${pathToBeUsed}/${profileFileName}`; - return RNFS.exists(newFilePath) - .then((fileExists) => { - if (!fileExists) { - return; - } + try { + const fileExists = await RNFS.exists(newFilePath); + if (fileExists) { + await RNFS.unlink(newFilePath); + Log.hmmm('[ProfilingToolMenu] existing file deleted successfully'); + } + } catch (error) { + const typedError = error as Error; + Log.hmmm('[ProfilingToolMenu] error checking/deleting existing file: ', typedError.message); + } + + try { + await RNFS.copyFile(profilePath, newFilePath); + zipRef.current?.file(infoFileName, appInfo); - return RNFS.unlink(newFilePath).then(() => { - Log.hmmm('[ProfilingToolMenu] existing file deleted successfully'); - }); - }) - .catch((error) => { - const typedError = error as Error; - Log.hmmm('[ProfilingToolMenu] error checking/deleting existing file: ', typedError.message); - }) - .then(() => RNFS.copyFile(profilePath, newFilePath)) - .then(() => { - zipRef.current?.file(infoFileName, appInfo); + await onDisableLogging(logsWithParsedMessages); + cleanupAfterDisable(); + onDownloadZip?.(); - return onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - onDownloadZip?.(); - }); - }) - .then(() => { - setProfileTracePath?.(newFilePath); - Log.hmmm('[ProfilingToolMenu] file copied successfully'); - }) - .catch((error) => { - Log.hmmm('[ProfilingToolMenu] error copying file: ', error); - }); + setProfileTracePath?.(newFilePath); + Log.hmmm('[ProfilingToolMenu] file copied successfully'); + } catch (error) { + Log.hmmm('[ProfilingToolMenu] error copying file: ', error); + } } diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts index 04f58a4b8c08..537bcca33842 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts @@ -1,6 +1,6 @@ import type {StopRecordingParams} from './handleStopRecording.types'; -export default function handleStopRecording({ +export default async function handleStopRecording({ infoFileName, appInfo, logsWithParsedMessages, @@ -11,8 +11,7 @@ export default function handleStopRecording({ }: StopRecordingParams): Promise { zipRef.current?.file(infoFileName, appInfo); - return onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - onDownloadZip?.(); - }); + await onDisableLogging(logsWithParsedMessages); + cleanupAfterDisable(); + onDownloadZip?.(); } diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts index 04f58a4b8c08..537bcca33842 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts @@ -1,6 +1,6 @@ import type {StopRecordingParams} from './handleStopRecording.types'; -export default function handleStopRecording({ +export default async function handleStopRecording({ infoFileName, appInfo, logsWithParsedMessages, @@ -11,8 +11,7 @@ export default function handleStopRecording({ }: StopRecordingParams): Promise { zipRef.current?.file(infoFileName, appInfo); - return onDisableLogging(logsWithParsedMessages).then(() => { - cleanupAfterDisable(); - onDownloadZip?.(); - }); + await onDisableLogging(logsWithParsedMessages); + cleanupAfterDisable(); + onDownloadZip?.(); } diff --git a/src/libs/actions/Troubleshoot.ts b/src/libs/actions/Troubleshoot.ts index 3ca4c72d9521..4b483c69627b 100644 --- a/src/libs/actions/Troubleshoot.ts +++ b/src/libs/actions/Troubleshoot.ts @@ -43,23 +43,21 @@ function clearAutoOffTimeout() { * @param fileName - The filename to save the profile trace as * @returns Profile path, memoize stats, and performance measures */ -function stopProfilingAndGetData(fileName: string): Promise { +async function stopProfilingAndGetData(fileName: string): Promise { const showProfileTool = shouldShowProfileTool(); // Stop profiler and save to file (only if profiling is available) - const profilingPromise = showProfileTool ? stopProfiling(true, fileName) : Promise.resolve(undefined); + const profilePath = showProfileTool ? await stopProfiling(true, fileName) : undefined; - return profilingPromise.then((profilePath) => { - // Get stats before stopping monitoring - const memoizeStats = Memoize.stopMonitoring(); - const performanceMeasures = showProfileTool ? Performance.getPerformanceMeasures() : undefined; + // Get stats before stopping monitoring + const memoizeStats = Memoize.stopMonitoring(); + const performanceMeasures = showProfileTool ? Performance.getPerformanceMeasures() : undefined; - // Stop monitoring - Performance.disableMonitoring(); - toggleProfileTool(false); + // Stop monitoring + Performance.disableMonitoring(); + toggleProfileTool(false); - return {profilePath, memoizeStats, performanceMeasures}; - }); + return {profilePath, memoizeStats, performanceMeasures}; } /** From 473031c24e7c801a6f36f722b4b00271241ee929 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 10 Dec 2025 21:55:30 +0100 Subject: [PATCH 08/11] fix lint --- .../BaseRecordTroubleshootDataToolMenu.tsx | 14 ++++++---- .../handleStopRecording.android.ts | 6 ++--- .../handleStopRecording.ios.ts | 9 ++++--- .../handleStopRecording.native.ts | 2 +- .../handleStopRecording.ts | 26 +++++++++++++++++++ .../handleStopRecording.types.ts | 2 +- .../handleStopRecording.web.ts | 2 +- 7 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts diff --git a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx index 3b54fde1927f..4f2aec7a2a4a 100644 --- a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx +++ b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx @@ -17,10 +17,10 @@ import getPlatform from '@libs/getPlatform'; import CONFIG from '@src/CONFIG'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Log as OnyxLog} from '@src/types/onyx'; +import pkg from '../../../package.json'; import handleStopRecording from './handleStopRecording'; -import type {StopRecordingParams} from './handleStopRecording.types'; +import type StopRecordingParams from './handleStopRecording.types'; import Share from './Share'; -import pkg from '../../../package.json'; type File = { path: string; @@ -141,9 +141,11 @@ function BaseRecordTroubleshootDataToolMenu({ }; await handleStopRecording(params); - } finally { - setIsDisabled(false); + } catch (error) { + console.error('[ProfilingToolMenu] error handling stop recording', error); } + + setIsDisabled(false); }; useEffect(() => { @@ -166,7 +168,9 @@ function BaseRecordTroubleshootDataToolMenu({ { + onToggle().catch((error) => console.error('[ProfilingToolMenu] toggle failed', error)); + }} disabled={isDisabled} /> diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts index 5b50fa52bcc8..c71430f76425 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts @@ -1,5 +1,5 @@ import RNFetchBlob from 'react-native-blob-util'; -import type {StopRecordingParams} from './handleStopRecording.types'; +import type StopRecordingParams from './handleStopRecording.types'; export default async function handleStopRecording({ profilingData, @@ -17,9 +17,7 @@ export default async function handleStopRecording({ if (profilePath) { try { // Check if it is an internal path of `DownloadManager` then append content://media to create a valid url - const {path} = await RNFetchBlob.fs.stat( - !profilePath.startsWith('content://media/') && profilePath.match(/\/downloads\/\d+$/) ? `content://media/${profilePath}` : profilePath, - ); + const {path} = await RNFetchBlob.fs.stat(!profilePath.startsWith('content://media/') && profilePath.match(/\/downloads\/\d+$/) ? `content://media/${profilePath}` : profilePath); setProfileTracePath?.(path); } catch { setProfileTracePath?.(profilePath); diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts index d14ff4b57e5e..5a18c1ea5511 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts @@ -1,6 +1,6 @@ import RNFS from 'react-native-fs'; import Log from '@libs/Log'; -import type {StopRecordingParams} from './handleStopRecording.types'; +import type StopRecordingParams from './handleStopRecording.types'; export default async function handleStopRecording({ profilingData, @@ -31,8 +31,8 @@ export default async function handleStopRecording({ Log.hmmm('[ProfilingToolMenu] existing file deleted successfully'); } } catch (error) { - const typedError = error as Error; - Log.hmmm('[ProfilingToolMenu] error checking/deleting existing file: ', typedError.message); + const message = error instanceof Error ? error.message : String(error); + Log.hmmm('[ProfilingToolMenu] error checking/deleting existing file: ', message); } try { @@ -46,6 +46,7 @@ export default async function handleStopRecording({ setProfileTracePath?.(newFilePath); Log.hmmm('[ProfilingToolMenu] file copied successfully'); } catch (error) { - Log.hmmm('[ProfilingToolMenu] error copying file: ', error); + const message = error instanceof Error ? error.message : String(error); + Log.hmmm('[ProfilingToolMenu] error copying file: ', message); } } diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts index 537bcca33842..5351abb9b1f0 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts @@ -1,4 +1,4 @@ -import type {StopRecordingParams} from './handleStopRecording.types'; +import type StopRecordingParams from './handleStopRecording.types'; export default async function handleStopRecording({ infoFileName, diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts new file mode 100644 index 000000000000..d236f02f4589 --- /dev/null +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts @@ -0,0 +1,26 @@ +import {Platform} from 'react-native'; +import handleStopRecordingAndroid from './handleStopRecording.android'; +import handleStopRecordingIOS from './handleStopRecording.ios'; +import handleStopRecordingNative from './handleStopRecording.native'; +import type StopRecordingParams from './handleStopRecording.types'; +import handleStopRecordingWeb from './handleStopRecording.web'; + +type HandleStopRecording = (params: StopRecordingParams) => Promise; + +const handleStopRecording: HandleStopRecording = (params) => { + if (Platform.OS === 'ios') { + return handleStopRecordingIOS(params); + } + + if (Platform.OS === 'android') { + return handleStopRecordingAndroid(params); + } + + if (Platform.OS === 'web') { + return handleStopRecordingWeb(params); + } + + return handleStopRecordingNative(params); +}; + +export default handleStopRecording; diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts index e199aa3dbb9b..19eebde4df72 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.types.ts @@ -17,4 +17,4 @@ type StopRecordingParams = { setProfileTracePath?: (path: string) => void; }; -export type {StopRecordingParams}; +export default StopRecordingParams; diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts index 537bcca33842..5351abb9b1f0 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts @@ -1,4 +1,4 @@ -import type {StopRecordingParams} from './handleStopRecording.types'; +import type StopRecordingParams from './handleStopRecording.types'; export default async function handleStopRecording({ infoFileName, From 10ed019621b68e492d39da90c016b334118247e4 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Thu, 11 Dec 2025 18:20:40 +0100 Subject: [PATCH 09/11] fix issue with troubleshoot on/off failure --- src/libs/ExportOnyxState/index.native.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libs/ExportOnyxState/index.native.ts b/src/libs/ExportOnyxState/index.native.ts index 12cfb612ab1c..8e7e5ad04193 100644 --- a/src/libs/ExportOnyxState/index.native.ts +++ b/src/libs/ExportOnyxState/index.native.ts @@ -7,9 +7,18 @@ import type OnyxState from '@src/types/onyx/OnyxState'; import {maskOnyxState} from './common'; import type {ExportOnyxStateModule, ReadFromOnyxDatabase, ShareAsFile} from './types'; +let onyxDb: ReturnType | null = null; + +function getOnyxDb() { + if (!onyxDb) { + onyxDb = open({name: CONST.DEFAULT_DB_NAME}); + } + return onyxDb; +} + const readFromOnyxDatabase: ReadFromOnyxDatabase = () => new Promise((resolve) => { - const db = open({name: CONST.DEFAULT_DB_NAME}); + const db = getOnyxDb(); const query = `SELECT * FROM ${CONST.DEFAULT_TABLE_NAME}`; db.executeAsync(query, []).then(({rows}) => { From c06db73729fa375c1a3ac53be70428fcae399f00 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 17 Dec 2025 18:14:07 +0100 Subject: [PATCH 10/11] fix comments --- ...ing.native.ts => finalizeStopRecording.ts} | 9 ++++- .../handleStopRecording.android.ts | 15 ++++--- .../handleStopRecording.ios.ts | 15 ++++--- .../handleStopRecording.ts | 39 +++++++++---------- .../handleStopRecording.web.ts | 17 -------- 5 files changed, 46 insertions(+), 49 deletions(-) rename src/components/RecordTroubleshootDataToolMenu/{handleStopRecording.native.ts => finalizeStopRecording.ts} (54%) delete mode 100644 src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts b/src/components/RecordTroubleshootDataToolMenu/finalizeStopRecording.ts similarity index 54% rename from src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts rename to src/components/RecordTroubleshootDataToolMenu/finalizeStopRecording.ts index 5351abb9b1f0..f2b695eb9697 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.native.ts +++ b/src/components/RecordTroubleshootDataToolMenu/finalizeStopRecording.ts @@ -1,6 +1,11 @@ import type StopRecordingParams from './handleStopRecording.types'; -export default async function handleStopRecording({ +type FinalizeStopRecordingParams = Pick< + StopRecordingParams, + 'infoFileName' | 'appInfo' | 'logsWithParsedMessages' | 'onDisableLogging' | 'cleanupAfterDisable' | 'zipRef' | 'onDownloadZip' +>; + +export default async function finalizeStopRecording({ infoFileName, appInfo, logsWithParsedMessages, @@ -8,7 +13,7 @@ export default async function handleStopRecording({ cleanupAfterDisable, zipRef, onDownloadZip, -}: StopRecordingParams): Promise { +}: FinalizeStopRecordingParams): Promise { zipRef.current?.file(infoFileName, appInfo); await onDisableLogging(logsWithParsedMessages); diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts index c71430f76425..194f9810b989 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.android.ts @@ -1,4 +1,5 @@ import RNFetchBlob from 'react-native-blob-util'; +import finalizeStopRecording from './finalizeStopRecording'; import type StopRecordingParams from './handleStopRecording.types'; export default async function handleStopRecording({ @@ -24,9 +25,13 @@ export default async function handleStopRecording({ } } - zipRef.current?.file(infoFileName, appInfo); - - await onDisableLogging(logsWithParsedMessages); - cleanupAfterDisable(); - onDownloadZip?.(); + await finalizeStopRecording({ + infoFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + onDownloadZip, + }); } diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts index 5a18c1ea5511..1f4a28d17953 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ios.ts @@ -1,5 +1,6 @@ import RNFS from 'react-native-fs'; import Log from '@libs/Log'; +import finalizeStopRecording from './finalizeStopRecording'; import type StopRecordingParams from './handleStopRecording.types'; export default async function handleStopRecording({ @@ -37,11 +38,15 @@ export default async function handleStopRecording({ try { await RNFS.copyFile(profilePath, newFilePath); - zipRef.current?.file(infoFileName, appInfo); - - await onDisableLogging(logsWithParsedMessages); - cleanupAfterDisable(); - onDownloadZip?.(); + await finalizeStopRecording({ + infoFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + onDownloadZip, + }); setProfileTracePath?.(newFilePath); Log.hmmm('[ProfilingToolMenu] file copied successfully'); diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts index d236f02f4589..09e101799b10 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts @@ -1,26 +1,25 @@ -import {Platform} from 'react-native'; -import handleStopRecordingAndroid from './handleStopRecording.android'; -import handleStopRecordingIOS from './handleStopRecording.ios'; -import handleStopRecordingNative from './handleStopRecording.native'; +import finalizeStopRecording from './finalizeStopRecording'; import type StopRecordingParams from './handleStopRecording.types'; -import handleStopRecordingWeb from './handleStopRecording.web'; type HandleStopRecording = (params: StopRecordingParams) => Promise; -const handleStopRecording: HandleStopRecording = (params) => { - if (Platform.OS === 'ios') { - return handleStopRecordingIOS(params); - } - - if (Platform.OS === 'android') { - return handleStopRecordingAndroid(params); - } - - if (Platform.OS === 'web') { - return handleStopRecordingWeb(params); - } - - return handleStopRecordingNative(params); -}; +const handleStopRecording: HandleStopRecording = ({ + infoFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + onDownloadZip, +}) => + finalizeStopRecording({ + infoFileName, + appInfo, + logsWithParsedMessages, + onDisableLogging, + cleanupAfterDisable, + zipRef, + onDownloadZip, + }); export default handleStopRecording; diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts deleted file mode 100644 index 5351abb9b1f0..000000000000 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.web.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type StopRecordingParams from './handleStopRecording.types'; - -export default async function handleStopRecording({ - infoFileName, - appInfo, - logsWithParsedMessages, - onDisableLogging, - cleanupAfterDisable, - zipRef, - onDownloadZip, -}: StopRecordingParams): Promise { - zipRef.current?.file(infoFileName, appInfo); - - await onDisableLogging(logsWithParsedMessages); - cleanupAfterDisable(); - onDownloadZip?.(); -} From 371ff8bdf0f3d676783e689b503732b8beca12bf Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 17 Dec 2025 18:30:04 +0100 Subject: [PATCH 11/11] fix prettier and compiler --- .../BaseRecordTroubleshootDataToolMenu.tsx | 6 +++--- .../finalizeStopRecording.ts | 5 +---- .../handleStopRecording.ts | 10 +--------- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx index 4771d95a289c..ca4b46d94a9a 100644 --- a/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx +++ b/src/components/RecordTroubleshootDataToolMenu/BaseRecordTroubleshootDataToolMenu.tsx @@ -1,6 +1,6 @@ import type JSZip from 'jszip'; import type {RefObject} from 'react'; -import React, {useCallback, useEffect, useState} from 'react'; +import React, {useEffect, useState} from 'react'; import {Alert} from 'react-native'; import DeviceInfo from 'react-native-device-info'; import Button from '@components/Button'; @@ -85,7 +85,7 @@ function BaseRecordTroubleshootDataToolMenu({ const [isDisabled, setIsDisabled] = useState(false); const [profileTracePath, setProfileTracePath] = useState(); - const getAppInfo = useCallback(async (profilingData: ProfilingData) => { + const getAppInfo = async (profilingData: ProfilingData) => { const [totalMemory, usedMemory] = await Promise.all([DeviceInfo.getTotalMemory(), DeviceInfo.getUsedMemory()]); return JSON.stringify({ appVersion: pkg.version, @@ -96,7 +96,7 @@ function BaseRecordTroubleshootDataToolMenu({ memoizeStats: profilingData.memoizeStats, performance: profilingData.performanceMeasures, }); - }, []); + }; const onToggle = async () => { if (!shouldRecordTroubleshootData) { diff --git a/src/components/RecordTroubleshootDataToolMenu/finalizeStopRecording.ts b/src/components/RecordTroubleshootDataToolMenu/finalizeStopRecording.ts index f2b695eb9697..7fb670ff1bfd 100644 --- a/src/components/RecordTroubleshootDataToolMenu/finalizeStopRecording.ts +++ b/src/components/RecordTroubleshootDataToolMenu/finalizeStopRecording.ts @@ -1,9 +1,6 @@ import type StopRecordingParams from './handleStopRecording.types'; -type FinalizeStopRecordingParams = Pick< - StopRecordingParams, - 'infoFileName' | 'appInfo' | 'logsWithParsedMessages' | 'onDisableLogging' | 'cleanupAfterDisable' | 'zipRef' | 'onDownloadZip' ->; +type FinalizeStopRecordingParams = Pick; export default async function finalizeStopRecording({ infoFileName, diff --git a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts index 09e101799b10..90f32b3b584a 100644 --- a/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts +++ b/src/components/RecordTroubleshootDataToolMenu/handleStopRecording.ts @@ -3,15 +3,7 @@ import type StopRecordingParams from './handleStopRecording.types'; type HandleStopRecording = (params: StopRecordingParams) => Promise; -const handleStopRecording: HandleStopRecording = ({ - infoFileName, - appInfo, - logsWithParsedMessages, - onDisableLogging, - cleanupAfterDisable, - zipRef, - onDownloadZip, -}) => +const handleStopRecording: HandleStopRecording = ({infoFileName, appInfo, logsWithParsedMessages, onDisableLogging, cleanupAfterDisable, zipRef, onDownloadZip}) => finalizeStopRecording({ infoFileName, appInfo,