Call core dump from the bug reporting button(s) (#2783)
* Add coredump to refresh button - this one indicates that there should be something like a core dump that is triggered. * Added lower right control bug report button - included custom toasts for bug reporting, supports fallback bug reporting when app cannot generate a core dump
This commit is contained in:
4
src-tauri/Cargo.lock
generated
4
src-tauri/Cargo.lock
generated
@ -4546,9 +4546,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.116"
|
version = "1.0.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"itoa 1.0.11",
|
"itoa 1.0.11",
|
||||||
|
@ -25,6 +25,7 @@ import { LowerRightControls } from 'components/LowerRightControls'
|
|||||||
import ModalContainer from 'react-modal-promise'
|
import ModalContainer from 'react-modal-promise'
|
||||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
||||||
import Gizmo from 'components/Gizmo'
|
import Gizmo from 'components/Gizmo'
|
||||||
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
useRefreshSettings(paths.FILE + 'SETTINGS')
|
useRefreshSettings(paths.FILE + 'SETTINGS')
|
||||||
@ -55,7 +56,11 @@ export function App() {
|
|||||||
setHtmlRef(ref)
|
setHtmlRef(ref)
|
||||||
}, [ref])
|
}, [ref])
|
||||||
|
|
||||||
const { settings } = useSettingsAuthContext()
|
const { auth, settings } = useSettingsAuthContext()
|
||||||
|
const token = auth?.context?.token
|
||||||
|
|
||||||
|
const coreDumpManager = new CoreDumpManager(engineCommandManager, ref, token)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
app: { onboardingStatus },
|
app: { onboardingStatus },
|
||||||
} = settings.context
|
} = settings.context
|
||||||
@ -129,7 +134,7 @@ export function App() {
|
|||||||
<ModelingSidebar paneOpacity={paneOpacity} />
|
<ModelingSidebar paneOpacity={paneOpacity} />
|
||||||
<Stream />
|
<Stream />
|
||||||
{/* <CamToggle /> */}
|
{/* <CamToggle /> */}
|
||||||
<LowerRightControls>
|
<LowerRightControls coreDumpManager={coreDumpManager}>
|
||||||
<Gizmo />
|
<Gizmo />
|
||||||
</LowerRightControls>
|
</LowerRightControls>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,8 +6,18 @@ import { NetworkHealthIndicator } from 'components/NetworkHealthIndicator'
|
|||||||
import { HelpMenu } from './HelpMenu'
|
import { HelpMenu } from './HelpMenu'
|
||||||
import { Link, useLocation } from 'react-router-dom'
|
import { Link, useLocation } from 'react-router-dom'
|
||||||
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
|
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
|
||||||
|
import { coreDump } from 'lang/wasm'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
|
import openWindow from 'lib/openWindow'
|
||||||
|
|
||||||
export function LowerRightControls(props: React.PropsWithChildren) {
|
export function LowerRightControls({
|
||||||
|
children,
|
||||||
|
coreDumpManager,
|
||||||
|
}: {
|
||||||
|
children?: React.ReactNode
|
||||||
|
coreDumpManager?: CoreDumpManager
|
||||||
|
}) {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const filePath = useAbsoluteFilePath()
|
const filePath = useAbsoluteFilePath()
|
||||||
const linkOverrideClassName =
|
const linkOverrideClassName =
|
||||||
@ -15,9 +25,42 @@ export function LowerRightControls(props: React.PropsWithChildren) {
|
|||||||
|
|
||||||
const isPlayWright = window?.localStorage.getItem('playwright') === 'true'
|
const isPlayWright = window?.localStorage.getItem('playwright') === 'true'
|
||||||
|
|
||||||
|
async function reportbug(event: { preventDefault: () => void }) {
|
||||||
|
event?.preventDefault()
|
||||||
|
|
||||||
|
if (!coreDumpManager) {
|
||||||
|
// open default reporting option
|
||||||
|
openWindow('https://github.com/KittyCAD/modeling-app/issues/new/choose')
|
||||||
|
} else {
|
||||||
|
toast
|
||||||
|
.promise(
|
||||||
|
coreDump(coreDumpManager, true),
|
||||||
|
{
|
||||||
|
loading: 'Preparing bug report...',
|
||||||
|
success: 'Bug report opened in new window',
|
||||||
|
error: 'Unable to export a core dump. Using default reporting.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
success: {
|
||||||
|
// Note: this extended duration is especially important for Playwright e2e testing
|
||||||
|
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
|
||||||
|
duration: 6000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err: Error) => {
|
||||||
|
if (err) {
|
||||||
|
openWindow(
|
||||||
|
'https://github.com/KittyCAD/modeling-app/issues/new/choose'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="fixed bottom-2 right-2 flex flex-col items-end gap-3 pointer-events-none">
|
<section className="fixed bottom-2 right-2 flex flex-col items-end gap-3 pointer-events-none">
|
||||||
{props.children}
|
{children}
|
||||||
<menu className="flex items-center justify-end gap-3 pointer-events-auto">
|
<menu className="flex items-center justify-end gap-3 pointer-events-auto">
|
||||||
<a
|
<a
|
||||||
href={`https://github.com/KittyCAD/modeling-app/releases/tag/v${APP_VERSION}`}
|
href={`https://github.com/KittyCAD/modeling-app/releases/tag/v${APP_VERSION}`}
|
||||||
@ -28,6 +71,7 @@ export function LowerRightControls(props: React.PropsWithChildren) {
|
|||||||
v{isPlayWright ? '11.22.33' : APP_VERSION}
|
v{isPlayWright ? '11.22.33' : APP_VERSION}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
|
onClick={reportbug}
|
||||||
href="https://github.com/KittyCAD/modeling-app/issues/new/choose"
|
href="https://github.com/KittyCAD/modeling-app/issues/new/choose"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
|
@ -124,7 +124,6 @@ export const ModelingMachineProvider = ({
|
|||||||
token
|
token
|
||||||
)
|
)
|
||||||
useHotkeyWrapper(['meta + shift + .'], () => {
|
useHotkeyWrapper(['meta + shift + .'], () => {
|
||||||
console.warn('CoreDump: Initializing core dump')
|
|
||||||
toast.promise(
|
toast.promise(
|
||||||
coreDump(coreDumpManager, true),
|
coreDump(coreDumpManager, true),
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,25 @@
|
|||||||
|
import { coreDump } from 'lang/wasm'
|
||||||
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
import { CustomIcon } from './CustomIcon'
|
import { CustomIcon } from './CustomIcon'
|
||||||
|
import { engineCommandManager } from 'lib/singletons'
|
||||||
|
import React from 'react'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
|
|
||||||
|
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
|
||||||
|
const { auth } = useSettingsAuthContext()
|
||||||
|
const token = auth?.context?.token
|
||||||
|
const { htmlRef } = useStore((s) => ({
|
||||||
|
htmlRef: s.htmlRef,
|
||||||
|
}))
|
||||||
|
const coreDumpManager = new CoreDumpManager(
|
||||||
|
engineCommandManager,
|
||||||
|
htmlRef,
|
||||||
|
token
|
||||||
|
)
|
||||||
|
|
||||||
export function RefreshButton() {
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
if (window && 'plausible' in window) {
|
if (window && 'plausible' in window) {
|
||||||
const p = window.plausible as (
|
const p = window.plausible as (
|
||||||
@ -17,8 +35,26 @@ export function RefreshButton() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toast
|
||||||
|
.promise(
|
||||||
|
coreDump(coreDumpManager, true),
|
||||||
|
{
|
||||||
|
loading: 'Starting core dump...',
|
||||||
|
success: 'Core dump completed successfully',
|
||||||
|
error: 'Error while exporting core dump',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
success: {
|
||||||
|
// Note: this extended duration is especially important for Playwright e2e testing
|
||||||
|
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
|
||||||
|
duration: 6000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
// Window may not be available in some environments
|
// Window may not be available in some environments
|
||||||
window?.location.reload()
|
window?.location.reload()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -334,6 +334,7 @@ export async function coreDump(
|
|||||||
openGithubIssue: boolean = false
|
openGithubIssue: boolean = false
|
||||||
): Promise<CoreDumpInfo> {
|
): Promise<CoreDumpInfo> {
|
||||||
try {
|
try {
|
||||||
|
console.warn('CoreDump: Initializing core dump')
|
||||||
const dump: CoreDumpInfo = await coredump(coreDumpManager)
|
const dump: CoreDumpInfo = await coredump(coreDumpManager)
|
||||||
/* NOTE: this console output of the coredump should include the field
|
/* NOTE: this console output of the coredump should include the field
|
||||||
`github_issue_url` which is not in the uploaded coredump file.
|
`github_issue_url` which is not in the uploaded coredump file.
|
||||||
|
@ -13,6 +13,14 @@ import screenshot from 'lib/screenshot'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { VITE_KC_API_BASE_URL } from 'env'
|
import { VITE_KC_API_BASE_URL } from 'env'
|
||||||
|
|
||||||
|
/* eslint-disable suggest-no-throw/suggest-no-throw --
|
||||||
|
* All the throws in CoreDumpManager are intentional and should be caught and handled properly
|
||||||
|
* by the calling Promises with a catch block. The throws are essential to properly handling
|
||||||
|
* when the app isn't ready enough or otherwise unable to produce a core dump. By throwing
|
||||||
|
* instead of simply erroring, the code halts execution at the first point which it cannot
|
||||||
|
* complete the core dump request.
|
||||||
|
**/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CoreDumpManager module
|
* CoreDumpManager module
|
||||||
* - for getting all the values from the JS world to pass to the Rust world for a core dump.
|
* - for getting all the values from the JS world to pass to the Rust world for a core dump.
|
||||||
@ -22,6 +30,7 @@ import { VITE_KC_API_BASE_URL } from 'env'
|
|||||||
// CoreDumpManager is instantiated in ModelingMachineProvider and passed to coreDump() in wasm.ts
|
// CoreDumpManager is instantiated in ModelingMachineProvider and passed to coreDump() in wasm.ts
|
||||||
// The async function coreDump() handles any errors thrown in its Promise catch method and rethrows
|
// The async function coreDump() handles any errors thrown in its Promise catch method and rethrows
|
||||||
// them to so the toast handler in ModelingMachineProvider can show the user an error message toast
|
// them to so the toast handler in ModelingMachineProvider can show the user an error message toast
|
||||||
|
// TODO: Throw more
|
||||||
export class CoreDumpManager {
|
export class CoreDumpManager {
|
||||||
engineCommandManager: EngineCommandManager
|
engineCommandManager: EngineCommandManager
|
||||||
htmlRef: React.RefObject<HTMLDivElement> | null
|
htmlRef: React.RefObject<HTMLDivElement> | null
|
||||||
|
Reference in New Issue
Block a user