mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-03 12:09:09 +02:00
add custom error dialog
This commit is contained in:
@@ -1,42 +1,30 @@
|
||||
import { Dialogs } from "@wailsio/runtime";
|
||||
import { WindowManager } from "@bindings/services";
|
||||
|
||||
import { isWindows } from "@/lib/platform";
|
||||
// Options for errorDialog. Kept as a {Title, Message} object so the many
|
||||
// existing call sites read unchanged after the switch from the native OS
|
||||
// MessageBox to the custom window below.
|
||||
export type ErrorDialogOptions = {
|
||||
Title: string;
|
||||
Message: string;
|
||||
};
|
||||
|
||||
// Derived from the runtime rather than deep-imported: the package's exports map
|
||||
// only exposes the types barrel, not "@wailsio/runtime/types/dialogs".
|
||||
type MessageDialogOptions = Parameters<typeof Dialogs.Error>[0];
|
||||
|
||||
// On Windows a native MessageBox attached to a parent window disables that
|
||||
// parent (WS_DISABLED) for the lifetime of the dialog and re-enables it on
|
||||
// dismissal. When the parent is the main window — whose WindowClosing hook
|
||||
// hides instead of closes (main.go) — the enable/hide sequence can race and
|
||||
// leave the window unable to process its close (X) button afterwards: the user
|
||||
// reports the main window can no longer be closed once an error dialog (e.g. a
|
||||
// rejected login) has been shown. Detaching the dialog gives the MessageBox a
|
||||
// NULL owner, so no window is ever disabled and the X keeps working.
|
||||
// errorDialog surfaces a user-actionable failure. It opens the custom,
|
||||
// frameless, always-on-top NetBird error window (modules/error/ErrorDialog.tsx
|
||||
// via Go WindowManager.OpenError) — it is NOT the native OS MessageBox any
|
||||
// more, despite the name.
|
||||
//
|
||||
// macOS keeps the attached (sheet-style) presentation — the bug is Windows-only
|
||||
// and detaching there loses the sheet animation — so we only force Detached on
|
||||
// Windows and leave any caller-supplied value untouched elsewhere.
|
||||
function withDetached(options: MessageDialogOptions): MessageDialogOptions {
|
||||
if (options.Detached !== undefined || !isWindows()) {
|
||||
return options;
|
||||
}
|
||||
return { ...options, Detached: true };
|
||||
}
|
||||
|
||||
export function errorDialog(options: MessageDialogOptions): Promise<string> {
|
||||
return Dialogs.Error(withDetached(options));
|
||||
}
|
||||
|
||||
export function warningDialog(options: MessageDialogOptions): Promise<string> {
|
||||
return Dialogs.Warning(withDetached(options));
|
||||
}
|
||||
|
||||
export function infoDialog(options: MessageDialogOptions): Promise<string> {
|
||||
return Dialogs.Info(withDetached(options));
|
||||
}
|
||||
|
||||
export function questionDialog(options: MessageDialogOptions): Promise<string> {
|
||||
return Dialogs.Question(withDetached(options));
|
||||
// Why the native box is gone: on Windows a native MessageBox attached to a
|
||||
// parent window disables that window (WS_DISABLED) for its lifetime, and the
|
||||
// main window's WindowClosing hook hides instead of closing — the two raced
|
||||
// and could leave the main window unable to process its close (X) button after
|
||||
// an error was shown. The custom window has its own chrome and never touches
|
||||
// another window's enabled state, so that class of bug is gone (and with it
|
||||
// the old `Detached: true` Windows-only workaround, plus the warning/info/
|
||||
// question wrappers that nothing called).
|
||||
//
|
||||
// Title and message must already be localised. Resolves as soon as the window
|
||||
// is opened (it does not block until the user dismisses it), so `await`ing
|
||||
// callers continue immediately after the dialog appears.
|
||||
export function errorDialog(options: ErrorDialogOptions): Promise<void> {
|
||||
return WindowManager.OpenError(options.Title, options.Message);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export const formatErrorMessage = (e: unknown): string => {
|
||||
const short = typeof ce.short === "string" ? ce.short : "";
|
||||
const long = typeof ce.long === "string" ? ce.long : "";
|
||||
if (short && long && long !== short) {
|
||||
return `${short}\n\nDetails: ${long}`;
|
||||
return `${short} Details: ${long}`;
|
||||
}
|
||||
if (short) return short;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user