-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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: Debug console view #36337
feat: Debug console view #36337
Conversation
This reverts commit 88d2e8b.
Reviewer Checklist
Screenshots/VideosAndroid: mWeb ChromeCleanShot.2024-02-14.at.15.29.59.mp4iOS: NativeCleanShot.2024-02-14.at.13.58.13.mp4iOS: mWeb SafariCleanShot.2024-02-14.at.14.18.03.mp4MacOS: Chrome / SafariCleanShot.2024-02-14.at.13.50.40.mp4MacOS: DesktopCleanShot.2024-02-14.at.15.36.33.mp4 |
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.
Looks good. Left some comments about the code.
@@ -320,7 +320,7 @@ function Button( | |||
shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined, | |||
shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined, | |||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing | |||
'text' in rest && (rest?.icon || rest?.shouldShowRightIcon) ? styles.alignItemsStretch : undefined, | |||
'text' in rest && rest?.shouldShowRightIcon ? styles.alignItemsStretch : undefined, |
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.
Any reason for this change?
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.
Confirmation for that change was here
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.
* @param textContent content of the file | ||
* @returns path, filename and size of the newly created file | ||
*/ | ||
const localFileCreate = (fileName: string, textContent: string) => { |
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 create a new types.ts
file and add the type for localFileCreate
type LocalFileCreate = (fileName: string, textContent: string) => Promise<{path: string, newFileName: string, size: number}>
@@ -1,6 +1,6 @@ | |||
import {Share} from 'react-native'; | |||
import RNFetchBlob from 'react-native-blob-util'; | |||
import * as FileUtils from '@libs/fileDownload/FileUtils'; | |||
import localFileCreate from '@libs/localFileCreate/index.native'; |
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.
import localFileCreate from '@libs/localFileCreate/index.native'; | |
import localFileCreate from '@libs/localFileCreate'; |
src/libs/localFileDownload/index.ts
Outdated
localFileCreate(fileName, textContent).then(({path}) => { | ||
const link = document.createElement('a'); | ||
link.download = FileUtils.appendTimeToFileName(`${fileName}.txt`); | ||
link.href = path; | ||
link.click(); | ||
}); |
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.
localFileCreate(fileName, textContent).then(({path}) => { | |
const link = document.createElement('a'); | |
link.download = FileUtils.appendTimeToFileName(`${fileName}.txt`); | |
link.href = path; | |
link.click(); | |
}); | |
localFileCreate(`${fileName}.txt`, textContent).then(({path, newFileName}) => { | |
const link = document.createElement('a'); | |
link.download = newFileName; | |
link.href = path; | |
link.click(); | |
}); |
localFileCreate
should append Time to FileName
* @param logs Logs captured on the current device | ||
* @returns CapturedLogs with parsed messages | ||
*/ | ||
const parseStingifiedMessages = (logs: Log[]) => { |
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.
const parseStingifiedMessages = (logs: Log[]) => { | |
const parseStringifyMessages = (logs: Log[]) => { |
little typo
useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ENTER, executeArbitraryCode); | ||
|
||
const saveLogs = () => { | ||
const logsWithParsedMessages = parseStingifiedMessages(logsList); |
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.
const logsWithParsedMessages = parseStingifiedMessages(logsList); | |
const logsWithParsedMessages = parseStringifyMessages(logsList); |
|
||
const shareLogs = () => { | ||
setIsGeneratingLogsFile(true); | ||
const logsWithParsedMessages = parseStingifiedMessages(logsList); |
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.
const logsWithParsedMessages = parseStingifiedMessages(logsList); | |
const logsWithParsedMessages = parseStringifyMessages(logsList); |
} | ||
|
||
setLogs((prevLogs) => ({...prevLogs, ...capturedLogs})); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps |
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.
Could you please add a comment explaining why this is needed? Just to make sure it won't be missed and removed in the future
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.
I think it was some kind of leftover that I missed, I think it is safe to remove it and pass shouldStoreLogs
to dependency array as well
type ShareLogPageProps = { | ||
route: { | ||
params: { | ||
source: string; | ||
}; | ||
}; | ||
}; |
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.
type ShareLogPageProps = { | |
route: { | |
params: { | |
source: string; | |
}; | |
}; | |
}; | |
type ShareLogPageProps = StackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.SHARE_LOG>; |
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.
Looks good to me.
@TMisiukiewicz Just a little question about this behavior: Why the |
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.
Looks good to me a few NABs that we can tackle later as well.
originalConsoleLog.apply(console, args); | ||
}; | ||
|
||
const charsToSanitize = /[\u2018\u2019\u201C\u201D\u201E\u2026]/g; |
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.
It would be nice to add a comment explaining a few of these chars and why we need to sanitize.
|
||
const charsToSanitize = /[\u2018\u2019\u201C\u201D\u201E\u2026]/g; | ||
|
||
const charMap: Record<string, string> = { |
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.
Maybe move this to before charsToSanitize
variable so we can map out unicode to string literals.
|
||
// Generate a file with the logs and pass its path to the list of reports to share it with | ||
localFileCreate('logs', JSON.stringify(logsWithParsedMessages, null, 2)).then(({path, size}) => { | ||
setIsGeneratingLogsFile(false); |
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.
NAB: Use finally for resetting the state?
|
||
const executeArbitraryCode = () => { | ||
const sanitizedInput = sanitizeConsoleInput(input); | ||
|
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.
NAB: Extra line, we can avoid the new lines if the variable is used immediately in the next line.
|
||
const saveLogs = () => { | ||
const logsWithParsedMessages = parseStringifyMessages(logsList); | ||
|
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.
NAB: new line.
Yeah, I agree. We can make the debug console accessible to users even if when they haven't turned on client side debugging. |
None of the above comments are concerning,, so I am going ahead with the merge. We have one discussion about having the debug console feature independently available https://expensify.slack.com/archives/C01GTK53T8Q/p1707932836441509?thread_ts=1703982689.203629&cid=C01GTK53T8Q, which we can tackle after a consensus. |
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/techievivek in version: 1.4.42-0 🚀
|
🚀 Deployed to production by https://github.com/chiragsalian in version: 1.4.42-5 🚀
|
return getOptions(reports, personalDetails, { | ||
betas, | ||
searchInputValue: searchValue.trim(), | ||
includeRecentReports: true, | ||
includeMultipleParticipantReports: true, | ||
sortByReportTypeInSearch: true, | ||
includePersonalDetails: true, | ||
forcePolicyNamePreview: true, | ||
includeOwnedWorkspaceChats: true, | ||
}); |
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.
Hello @TMisiukiewicz @fedirjh @techievivek
coming from this issue in which we want to modify the getOptions
params to include also the direct DM as one of the returned result, and I was suggesting here to include also the threads
.
So we are wondering if you have already discussed the possibility of enabling threads in the returned list.
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.
There might be deleted threads in the search results as well, and hence they might have disabled the threads option 🤔
Is this the case why threads were disabled?
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.
just a friendly reminder @TMisiukiewicz @fedirjh @techievivek
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.
cc @abzokhattab I don't know if there have been any discussions about allowing or preventing the sharing of logs within threads.
type ShareLogPageProps = StackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.SHARE_LOG>; | ||
|
||
function ShareLogPage({route}: ShareLogPageProps) { | ||
return <ShareLogList logSource={route.params.source} />; |
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.
While reviewing another PR, I found out that there will be crash if we open ShareLogPage
without source
query param. So I think we should add optional chaining here or wrap ShareLogPage
with FullPageNotFound view where we don't have source
query param.
Screen.Recording.2024-03-18.at.15.16.31.mov
data={logsList} | ||
renderItem={renderItem} | ||
contentContainerStyle={styles.p5} | ||
inverted |
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.
We should have used the existing InvertedFlatList, which has maintainVisibleContentPosition
set, to avoid auto-scrolling on new data. This caused a regression.
Details
Implementing the Debug console view, which displays logs from
Logger
in real time, with a possibility of saving it to the.txt
file or sharing it as an attachment in a report.Fixed Issues
$ #34082
PROPOSAL:
Tests
5+5
in the input below the console and press "Execute"10
was displayed in a consoleOffline tests
n/a
QA Steps
5+5
in the input below the console and press "Execute"10
was displayed in a consolePR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)Design
label so the design team can review the changes.ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Android: Native
ANDROID.mov
Android: mWeb Chrome
ANDROID.WEB.mov
iOS: Native
IOS.mov
iOS: mWeb Safari
IOS.WEB.mov
MacOS: Chrome / Safari
WEB.mov
MacOS: Desktop
DESKTOP.mov