Report uncaught Python exceptions with a GUI popup
This commit is contained in:
parent
eff64fabd6
commit
511681ae4d
3
TODO.md
3
TODO.md
|
@ -3,6 +3,9 @@
|
||||||
- Make dark bar extend down pane
|
- Make dark bar extend down pane
|
||||||
- Verify default size
|
- Verify default size
|
||||||
|
|
||||||
|
- catch py unretrieved exception
|
||||||
|
- call default handler from signin & others
|
||||||
|
|
||||||
## Media
|
## Media
|
||||||
|
|
||||||
- nio ClientTimeout
|
- nio ClientTimeout
|
||||||
|
|
|
@ -21,8 +21,10 @@ HPopup {
|
||||||
property alias details: details
|
property alias details: details
|
||||||
|
|
||||||
property string okText: qsTr("OK")
|
property string okText: qsTr("OK")
|
||||||
|
property string okIcon: "ok"
|
||||||
property bool okEnabled: true
|
property bool okEnabled: true
|
||||||
property bool okClicked: false
|
property bool okClicked: false
|
||||||
|
property string cancelText: qsTr("Cancel")
|
||||||
|
|
||||||
|
|
||||||
Binding on height {
|
Binding on height {
|
||||||
|
@ -40,8 +42,8 @@ HPopup {
|
||||||
clickButtonOnEnter: "ok"
|
clickButtonOnEnter: "ok"
|
||||||
|
|
||||||
buttonModel: [
|
buttonModel: [
|
||||||
{ name: "ok", text: okText, iconName: "ok", enabled: okEnabled},
|
{ name: "ok", text: okText, iconName: okIcon, enabled: okEnabled},
|
||||||
{ name: "cancel", text: qsTr("Cancel"), iconName: "cancel" },
|
{ name: "cancel", text: cancelText, iconName: "cancel" },
|
||||||
]
|
]
|
||||||
|
|
||||||
buttonCallbacks: ({
|
buttonCallbacks: ({
|
||||||
|
|
39
src/gui/Popups/UnexpectedErrorPopup.qml
Normal file
39
src/gui/Popups/UnexpectedErrorPopup.qml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import "../Base"
|
||||||
|
|
||||||
|
BoxPopup {
|
||||||
|
summary.text: qsTr("Unexpected error occured: <i>%1</i>").arg(errorType)
|
||||||
|
summary.textFormat: Text.StyledText
|
||||||
|
|
||||||
|
okText: qsTr("Report")
|
||||||
|
okIcon: "report-error"
|
||||||
|
okEnabled: false // TODO
|
||||||
|
cancelText: qsTr("Ignore")
|
||||||
|
box.focusButton: "cancel"
|
||||||
|
|
||||||
|
|
||||||
|
property string errorType
|
||||||
|
property var errorArguments: []
|
||||||
|
property string traceback: ""
|
||||||
|
|
||||||
|
|
||||||
|
HScrollableTextArea {
|
||||||
|
text: traceback || qsTr("No traceback available")
|
||||||
|
area.readOnly: true
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
HCheckBox {
|
||||||
|
text: qsTr("Hide this type of error until restart")
|
||||||
|
onCheckedChanged:
|
||||||
|
checked ?
|
||||||
|
window.hideErrorTypes.add(errorType) :
|
||||||
|
window.hideErrorTypes.delete(errorType)
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,21 +19,39 @@ QtObject {
|
||||||
let onSuccess = py.privates.pendingCoroutines[uuid].onSuccess
|
let onSuccess = py.privates.pendingCoroutines[uuid].onSuccess
|
||||||
let onError = py.privates.pendingCoroutines[uuid].onError
|
let onError = py.privates.pendingCoroutines[uuid].onError
|
||||||
|
|
||||||
|
delete py.privates.pendingCoroutines[uuid]
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
let type = py.getattr(py.getattr(error, "__class__"), "__name__")
|
const type = py.getattr(py.getattr(error, "__class__"), "__name__")
|
||||||
let args = py.getattr(error, "args")
|
const args = py.getattr(error, "args")
|
||||||
|
|
||||||
type === "CancelledError" ?
|
if (type === "CancelledError") {
|
||||||
console.warn(`python: cancelled: ${uuid}`) :
|
console.warn(`python: cancelled: ${uuid}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
onError ?
|
if (onError) {
|
||||||
onError(type, args, error, traceback) :
|
onError(type, args, error, traceback)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.error(`python: ${uuid}\n${traceback}`)
|
console.error(`python: ${uuid}\n${traceback}`)
|
||||||
|
|
||||||
} else if (onSuccess) { onSuccess(result) }
|
if (window.hideErrorTypes.has(type)) {
|
||||||
|
console.warn(
|
||||||
|
"Not showing error popup for this type due to user choice"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
delete py.privates.pendingCoroutines[uuid]
|
utils.makePopup(
|
||||||
|
"Popups/UnexpectedErrorPopup.qml",
|
||||||
|
window,
|
||||||
|
{ errorType: type, errorArguments: args, traceback },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onSuccess) onSuccess(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,8 @@ ApplicationWindow {
|
||||||
|
|
||||||
property var theme: null
|
property var theme: null
|
||||||
|
|
||||||
|
property var hideErrorTypes: new Set()
|
||||||
|
|
||||||
readonly property alias py: py
|
readonly property alias py: py
|
||||||
|
|
||||||
|
|
||||||
|
|
3
src/icons/thin/report-error.svg
Normal file
3
src/icons/thin/report-error.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg clip-rule="evenodd" fill-rule="evenodd" height="24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m24 17.98h-13l-7 5.02v-5.02h-4v-16.981h24zm-22-14.981v12.981h4v3.125l4.357-3.125h11.643v-12.981zm10 8.501c.69 0 1.25.56 1.25 1.25s-.56 1.25-1.25 1.25-1.25-.56-1.25-1.25.56-1.25 1.25-1.25zm1-6.5v5h-2v-5z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 330 B |
Loading…
Reference in New Issue
Block a user