-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: access client side logging from Test Tools Modal #38803
Changes from all commits
125f181
576786c
cc424f7
a6ea8bd
e2882ad
851831c
d0b6195
e807fce
fde28ad
13e7124
4b6ab28
5b54245
56790ae
d29bf47
a4979ec
0611f14
40e4fb3
25ebd15
17a8844
eb2184f
72d348e
155d7ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import React from 'react'; | ||
import {Alert} from 'react-native'; | ||
import {withOnyx} from 'react-native-onyx'; | ||
import type {OnyxEntry} from 'react-native-onyx'; | ||
import Button from '@components/Button'; | ||
import Switch from '@components/Switch'; | ||
import TestToolRow from '@components/TestToolRow'; | ||
import Text from '@components/Text'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import useThemeStyles from '@hooks/useThemeStyles'; | ||
import * as Console from '@libs/actions/Console'; | ||
import {parseStringifiedMessages} from '@libs/Console'; | ||
import ONYXKEYS from '@src/ONYXKEYS'; | ||
import type {CapturedLogs, Log} from '@src/types/onyx'; | ||
|
||
type BaseClientSideLoggingToolMenuOnyxProps = { | ||
/** Logs captured on the current device */ | ||
capturedLogs: OnyxEntry<CapturedLogs>; | ||
|
||
/** Whether or not logs should be stored */ | ||
shouldStoreLogs: OnyxEntry<boolean>; | ||
}; | ||
|
||
type BaseClientSideLoggingToolProps = { | ||
/** Locally created file */ | ||
file?: {path: string; newFileName: string; size: number}; | ||
/** Action to run when pressing Share button */ | ||
onShareLogs?: () => void; | ||
/** Action to run when disabling the switch */ | ||
onDisableLogging: (logs: Log[]) => void; | ||
/** Action to run when enabling logging */ | ||
onEnableLogging?: () => void; | ||
} & BaseClientSideLoggingToolMenuOnyxProps; | ||
|
||
function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onShareLogs, onDisableLogging, onEnableLogging}: BaseClientSideLoggingToolProps) { | ||
const {translate} = useLocalize(); | ||
|
||
const onToggle = () => { | ||
if (!shouldStoreLogs) { | ||
Console.setShouldStoreLogs(true); | ||
|
||
if (onEnableLogging) { | ||
onEnableLogging(); | ||
} | ||
|
||
return; | ||
} | ||
|
||
if (!capturedLogs) { | ||
Alert.alert(translate('initialSettingsPage.troubleshoot.noLogsToShare')); | ||
Console.disableLoggingAndFlushLogs(); | ||
return; | ||
} | ||
|
||
const logs = Object.values(capturedLogs); | ||
const logsWithParsedMessages = parseStringifiedMessages(logs); | ||
|
||
onDisableLogging(logsWithParsedMessages); | ||
Console.disableLoggingAndFlushLogs(); | ||
}; | ||
const styles = useThemeStyles(); | ||
return ( | ||
<> | ||
<TestToolRow title={translate('initialSettingsPage.troubleshoot.clientSideLogging')}> | ||
<Switch | ||
accessibilityLabel={translate('initialSettingsPage.troubleshoot.clientSideLogging')} | ||
isOn={!!shouldStoreLogs} | ||
onToggle={onToggle} | ||
/> | ||
</TestToolRow> | ||
{!!file && ( | ||
<> | ||
<Text style={[styles.textLabelSupporting, styles.mb4]}>{`path: ${file.path}`}</Text> | ||
<TestToolRow title={translate('initialSettingsPage.debugConsole.logs')}> | ||
<Button | ||
small | ||
text={translate('common.share')} | ||
onPress={onShareLogs} | ||
/> | ||
</TestToolRow> | ||
</> | ||
)} | ||
</> | ||
); | ||
} | ||
|
||
BaseClientSideLoggingToolMenu.displayName = 'BaseClientSideLoggingToolMenu'; | ||
|
||
export default withOnyx<BaseClientSideLoggingToolProps, BaseClientSideLoggingToolMenuOnyxProps>({ | ||
capturedLogs: { | ||
key: ONYXKEYS.LOGS, | ||
}, | ||
shouldStoreLogs: { | ||
key: ONYXKEYS.SHOULD_STORE_LOGS, | ||
}, | ||
})(BaseClientSideLoggingToolMenu); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React, {useState} from 'react'; | ||
import RNFetchBlob from 'react-native-blob-util'; | ||
import Share from 'react-native-share'; | ||
import type {Log} from '@libs/Console'; | ||
import localFileCreate from '@libs/localFileCreate'; | ||
import BaseClientSideLoggingToolMenu from './BaseClientSideLoggingToolMenu'; | ||
|
||
function ClientSideLoggingToolMenu() { | ||
const [file, setFile] = useState<{path: string; newFileName: string; size: number}>(); | ||
|
||
const createAndSaveFile = (logs: Log[]) => { | ||
localFileCreate('logs', JSON.stringify(logs, null, 2)).then((localFile) => { | ||
RNFetchBlob.MediaCollection.copyToMediaStore( | ||
{ | ||
name: localFile.newFileName, | ||
parentFolder: '', | ||
mimeType: 'text/plain', | ||
}, | ||
'Download', | ||
localFile.path, | ||
); | ||
Comment on lines
+13
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason to copy the files to the media store? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, on Android it is required to copy the file to media store to make it available in the public download directory There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hi @TMisiukiewicz was there a reason to first save the file in |
||
setFile(localFile); | ||
}); | ||
}; | ||
|
||
const shareLogs = () => { | ||
if (!file) { | ||
return; | ||
} | ||
Share.open({ | ||
url: `file://${file.path}`, | ||
}); | ||
}; | ||
|
||
return ( | ||
<BaseClientSideLoggingToolMenu | ||
file={file} | ||
onEnableLogging={() => setFile(undefined)} | ||
onDisableLogging={createAndSaveFile} | ||
onShareLogs={shareLogs} | ||
/> | ||
); | ||
} | ||
|
||
ClientSideLoggingToolMenu.displayName = 'ClientSideLoggingToolMenu'; | ||
|
||
export default ClientSideLoggingToolMenu; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React, {useState} from 'react'; | ||
import Share from 'react-native-share'; | ||
import type {Log} from '@libs/Console'; | ||
import localFileCreate from '@libs/localFileCreate'; | ||
import BaseClientSideLoggingToolMenu from './BaseClientSideLoggingToolMenu'; | ||
|
||
function ClientSideLoggingToolMenu() { | ||
const [file, setFile] = useState<{path: string; newFileName: string; size: number}>(); | ||
|
||
const createFile = (logs: Log[]) => { | ||
localFileCreate('logs', JSON.stringify(logs, null, 2)).then((localFile) => { | ||
setFile(localFile); | ||
}); | ||
}; | ||
|
||
const shareLogs = () => { | ||
if (!file) { | ||
return; | ||
} | ||
Share.open({ | ||
url: `file://${file.path}`, | ||
}); | ||
}; | ||
|
||
return ( | ||
<BaseClientSideLoggingToolMenu | ||
file={file} | ||
onEnableLogging={() => setFile(undefined)} | ||
onDisableLogging={createFile} | ||
onShareLogs={shareLogs} | ||
/> | ||
); | ||
} | ||
|
||
ClientSideLoggingToolMenu.displayName = 'ClientSideLoggingToolMenu'; | ||
|
||
export default ClientSideLoggingToolMenu; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React from 'react'; | ||
import type {Log} from '@libs/Console'; | ||
import localFileDownload from '@libs/localFileDownload'; | ||
import BaseClientSideLoggingToolMenu from './BaseClientSideLoggingToolMenu'; | ||
|
||
function ClientSideLoggingToolMenu() { | ||
const downloadFile = (logs: Log[]) => { | ||
localFileDownload('logs', JSON.stringify(logs, null, 2)); | ||
}; | ||
|
||
return <BaseClientSideLoggingToolMenu onDisableLogging={downloadFile} />; | ||
} | ||
|
||
ClientSideLoggingToolMenu.displayName = 'ClientSideLoggingToolMenu'; | ||
|
||
export default ClientSideLoggingToolMenu; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass
file
as a param inonShareLogs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or better remove the
onShareLogs
prop and let the button always callShare.open
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this has to be platform-specific, as there is no share option for web/desktop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's pass the file prop through onShareLogs for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually there is no benefit in doing this.