-
Notifications
You must be signed in to change notification settings - Fork 853
Handle import errors in popup data restore #956
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -568,13 +568,36 @@ export function GeneralPart({ config, updateConfig, setTabIndex }) { | |
| input.click() | ||
| }) | ||
| if (!file) return | ||
| const data = await new Promise((resolve) => { | ||
| const reader = new FileReader() | ||
| reader.onload = (e) => resolve(JSON.parse(e.target.result)) | ||
| reader.readAsText(file) | ||
| }) | ||
| await importDataIntoStorage(Browser.storage.local, data) | ||
| window.location.reload() | ||
| try { | ||
| const fileContent = | ||
| typeof file.text === 'function' | ||
| ? await file.text() | ||
| : await new Promise((resolve, reject) => { | ||
| const reader = new FileReader() | ||
| reader.onload = () => resolve(reader.result) | ||
| reader.onerror = () => reject(reader.error) | ||
| reader.readAsText(file) | ||
| }) | ||
| const parsedData = JSON.parse(fileContent) | ||
| const isPlainObject = | ||
| parsedData !== null && typeof parsedData === 'object' && !Array.isArray(parsedData) | ||
|
|
||
| if (!isPlainObject) { | ||
| throw new Error('Invalid backup file') | ||
PeterDaveHello marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| await importDataIntoStorage(Browser.storage.local, parsedData) | ||
| window.location.reload() | ||
| } catch (error) { | ||
| console.error('[popup] Failed to import data', error) | ||
| const rawMessage = | ||
| error instanceof SyntaxError | ||
| ? 'Invalid backup file' | ||
| : error instanceof Error | ||
PeterDaveHello marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ? error.message | ||
| : String(error ?? '') | ||
| window.alert(rawMessage ? `${t('Error')}: ${rawMessage}` : t('Error')) | ||
|
Comment on lines
+591
to
+599
Member
Author
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. @coderabbitai what do you think?
Contributor
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.
Since the full technical detail is already preserved in } catch (error) {
console.error('[popup] Failed to import data', error)
const displayMessage =
error instanceof SyntaxError
? t('Invalid backup file')
: error instanceof Error
? error.message
: String(error ?? '')
window.alert(displayMessage ? `${t('Error')}: ${displayMessage}` : t('Error'))
}This keeps the UX clean for parse failures while still surfacing meaningful messages for other error types (e.g., storage quota errors from |
||
| } | ||
|
Comment on lines
+571
to
+600
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. While the current implementation correctly handles errors, it can be simplified by using the try {
const fileContent = await file.text()
const data = JSON.parse(fileContent)
await importDataIntoStorage(Browser.storage.local, data)
window.location.reload()
} catch (error) {
console.error('[popup] Failed to import data', error)
window.alert(`${t('Error')}: ${error.message || error}`)
}
Member
Author
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. @coderabbitai what do you think?
Contributor
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. Ask❓@coderabbitai what do you think? Answer:The change is a solid improvement: wrapping the entire import flow in a A few concrete notes/suggestions:
Overall: 👍 good fix, and I’d recommend the
Contributor
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.
Contributor
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.
Why it's better:
Browser compatibility: One encoding note: Combined with the try {
const fileContent = await file.text()
const parsedData = JSON.parse(fileContent)
if (parsedData === null || typeof parsedData !== 'object' || Array.isArray(parsedData)) {
throw new Error('Invalid backup file')
}
await importDataIntoStorage(Browser.storage.local, data)
window.location.reload()
} catch (error) {
console.error('[popup] Failed to import data', error)
const message = error instanceof Error ? error.message : String(error ?? t('Error'))
window.alert(`${t('Error')}: ${message}`)
}This is cleaner and easier to follow than the |
||
| }} | ||
| > | ||
| {t('Import All Data')} | ||
|
|
||
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.
(Refers to lines 563-569)
📝 Info: Pre-existing: file picker cancel leaves a hanging promise
The file selection on lines 563-569 creates a Promise that only resolves via
input.onchange. In some browsers, if the user cancels the file dialog,onchangenever fires, leaving the Promise permanently pending. This is a pre-existing issue not introduced by this PR, and theif (!file) returnguard on line 570 only helps ifonchangefires with an empty file list. A common fix is to listen for afocusorchangeevent on the window/document afterinput.click()to detect cancellation, or to useinput.addEventListener('cancel', ...).Was this helpful? React with 👍 or 👎 to provide feedback.