🐛 fix(update): 修复重启更新时退出确认弹窗被遮挡

- 新增应用退出确认专用层级并动态高于当前设置子弹窗
- 未保存 SQL 与关闭其他实例确认框统一使用前景层级
- 补充更新退出链路与弹层层级回归测试
This commit is contained in:
Syngnat
2026-07-23 14:44:09 +08:00
parent 95992d739a
commit 1dcc866846
4 changed files with 29 additions and 2 deletions

View File

@@ -210,6 +210,7 @@ import {
saveApplicationQuitUnsavedSQLTargets,
} from './utils/sqlEditorApplicationQuit';
import {
APP_APPLICATION_QUIT_MODAL_Z_INDEX,
APP_FOREGROUND_MODAL_Z_INDEX,
APP_NESTED_MODAL_Z_INDEX,
APP_OVERLAY_Z_INDEX_BASE,
@@ -1064,6 +1065,10 @@ function App() {
APP_NESTED_MODAL_Z_INDEX,
settingsCenterModalZIndex + 100,
);
const applicationQuitModalZIndex = Math.max(
APP_APPLICATION_QUIT_MODAL_Z_INDEX,
settingsChildModalZIndex + 100,
);
const toggleAIPanel = useStore(state => state.toggleAIPanel);
const setAIPanelVisible = useStore(state => state.setAIPanelVisible);
useEffect(() => {
@@ -2608,6 +2613,7 @@ function App() {
cancelText: t('app.quit.unsaved_sql.cancel'),
closable: true,
maskClosable: false,
zIndex: applicationQuitModalZIndex,
okButtonProps: { danger: true, type: 'primary' },
footer: (_, { OkBtn, CancelBtn }) => (
<>
@@ -2643,7 +2649,7 @@ function App() {
});
destroyConfirm = confirmRef.destroy;
applicationQuitConfirmRef.current = confirmRef;
}, [forceQuitApplication, resetApplicationQuitRequest, saveQuery, t]);
}, [applicationQuitModalZIndex, forceQuitApplication, resetApplicationQuitRequest, saveQuery, t]);
const handleInstallUpdateRequest = useCallback(async () => {
if (installMode === 'portable' || installMode === 'msi') {
@@ -2654,6 +2660,7 @@ function App() {
cancelText: t('common.cancel'),
closable: true,
maskClosable: false,
zIndex: applicationQuitModalZIndex,
okButtonProps: { danger: true, type: 'primary' },
onOk: async () => {
await handleApplicationQuitRequest(() => handleInstallFromProgress(true));
@@ -2662,7 +2669,7 @@ function App() {
return;
}
await handleApplicationQuitRequest(() => handleInstallFromProgress(false));
}, [handleApplicationQuitRequest, handleInstallFromProgress, installMode, t]);
}, [applicationQuitModalZIndex, handleApplicationQuitRequest, handleInstallFromProgress, installMode, t]);
useEffect(() => {
const offBeforeClose = EventsOn('app:before-close-request', () => {

View File

@@ -43,4 +43,21 @@ describe('restart-to-update unsaved SQL guard', () => {
expect(appSource).toContain("updateInstallAction === 'launch-installer'");
expect(appSource.match(/\{updateInstallActionLabel\}/g)).toHaveLength(2);
});
it('keeps every update quit confirmation above active settings and update dialogs', () => {
const unsavedConfirmStart = appSource.indexOf('const confirmRef = Modal.confirm({');
const installRequestStart = appSource.indexOf('const handleInstallUpdateRequest = useCallback', unsavedConfirmStart);
const installRequestEnd = appSource.indexOf('\n\n useEffect(() => {', installRequestStart);
const unsavedConfirmSource = appSource.slice(unsavedConfirmStart, installRequestStart);
const installRequestSource = appSource.slice(installRequestStart, installRequestEnd);
expect(unsavedConfirmStart).toBeGreaterThan(-1);
expect(installRequestStart).toBeGreaterThan(unsavedConfirmStart);
expect(installRequestEnd).toBeGreaterThan(installRequestStart);
expect(appSource).toContain('APP_APPLICATION_QUIT_MODAL_Z_INDEX,');
expect(appSource).toContain('const applicationQuitModalZIndex = Math.max(');
expect(appSource).toContain('settingsChildModalZIndex + 100,');
expect(unsavedConfirmSource).toContain('zIndex: applicationQuitModalZIndex');
expect(installRequestSource).toContain('zIndex: applicationQuitModalZIndex');
});
});

View File

@@ -5,6 +5,7 @@ import * as ts from 'typescript';
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
APP_APPLICATION_QUIT_MODAL_Z_INDEX,
APP_COMMAND_PALETTE_Z_INDEX,
APP_DETACHED_WINDOW_Z_INDEX_BASE,
APP_FOREGROUND_MODAL_Z_INDEX,
@@ -110,6 +111,7 @@ describe('application overlay z-index policy', () => {
expect(APP_FOREGROUND_MODAL_Z_INDEX).toBeGreaterThan(APP_POPUP_Z_INDEX);
expect(APP_NESTED_MODAL_Z_INDEX).toBeGreaterThan(APP_FOREGROUND_MODAL_Z_INDEX);
expect(APP_COMMAND_PALETTE_Z_INDEX).toBeGreaterThan(APP_NESTED_MODAL_Z_INDEX);
expect(APP_APPLICATION_QUIT_MODAL_Z_INDEX).toBeGreaterThan(APP_COMMAND_PALETTE_Z_INDEX);
});
it('configures static Ant Design APIs with the same popup base', () => {

View File

@@ -6,6 +6,7 @@ export const APP_POPUP_Z_INDEX = APP_OVERLAY_Z_INDEX_BASE + 9_000;
export const APP_FOREGROUND_MODAL_Z_INDEX = APP_OVERLAY_Z_INDEX_BASE + 10_000;
export const APP_NESTED_MODAL_Z_INDEX = APP_FOREGROUND_MODAL_Z_INDEX + 1_000;
export const APP_COMMAND_PALETTE_Z_INDEX = APP_NESTED_MODAL_Z_INDEX + 1_000;
export const APP_APPLICATION_QUIT_MODAL_Z_INDEX = APP_COMMAND_PALETTE_Z_INDEX + 1_000;
export const configureAntdStaticOverlayLayer = (): void => {
ConfigProvider.config({