mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-11 09:13:36 +08:00
🐛 fix(query-editor): 修正 SQL 保存代码错位
- 恢复保存队列与组件挂载状态的声明位置 - 修正草稿同步、保存完成判断和结果关闭逻辑结构 - 恢复保存查询回归用例并补齐异步等待
This commit is contained in:
@@ -7862,6 +7862,13 @@ describe('QueryEditor external SQL save', () => {
|
||||
createdAt: 100,
|
||||
},
|
||||
];
|
||||
storeState.saveQuery.mockImplementationOnce(async (savedQuery: SavedQuery) => {
|
||||
storeState.savedQueries = storeState.savedQueries.map((item) => (
|
||||
item.id === savedQuery.id ? savedQuery : item
|
||||
));
|
||||
storeSubscribers.forEach((subscriber) => subscriber());
|
||||
return savedQuery;
|
||||
});
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
@@ -7875,7 +7882,7 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(getQueryTabDraft('tab-1')).toBe('select 3;');
|
||||
|
||||
await act(async () => {
|
||||
findButton(renderer!, '保存').props.onClick();
|
||||
await findButton(renderer!, '保存').props.onClick();
|
||||
});
|
||||
|
||||
expect(backendApp.WriteSQLFile).not.toHaveBeenCalled();
|
||||
@@ -7887,75 +7894,6 @@ describe('QueryEditor external SQL save', () => {
|
||||
dbName: 'main',
|
||||
createdAt: 100,
|
||||
}));
|
||||
});
|
||||
|
||||
it('keeps untitled fallback when the new query tab title is localized', async () => {
|
||||
setCurrentLanguage('en-US');
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({ title: 'New Query', savedQueryId: 'saved-1' })} />);
|
||||
});
|
||||
|
||||
editorState.value = 'select 8;';
|
||||
|
||||
await act(async () => {
|
||||
findButton(renderer!, 'Save').props.onClick();
|
||||
});
|
||||
|
||||
expect(storeState.saveQuery).toHaveBeenCalledWith(expect.objectContaining({
|
||||
id: 'saved-1',
|
||||
name: 'Untitled query',
|
||||
sql: 'select 8;',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'main',
|
||||
}));
|
||||
});
|
||||
|
||||
it('keeps untitled fallback after a language switch when the tab title came from another locale', async () => {
|
||||
setCurrentLanguage('ja-JP');
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({ title: 'New Query', savedQueryId: 'saved-1' })} />);
|
||||
});
|
||||
|
||||
editorState.value = 'select 10;';
|
||||
|
||||
await act(async () => {
|
||||
findButton(renderer!, '保存').props.onClick();
|
||||
});
|
||||
|
||||
expect(storeState.saveQuery).toHaveBeenCalledWith(expect.objectContaining({
|
||||
id: 'saved-1',
|
||||
storeState.saveQuery.mockImplementationOnce(async (savedQuery: SavedQuery) => {
|
||||
storeState.savedQueries = storeState.savedQueries.map((item) => (
|
||||
item.id === savedQuery.id ? savedQuery : item
|
||||
));
|
||||
storeSubscribers.forEach((subscriber) => subscriber());
|
||||
return savedQuery;
|
||||
});
|
||||
name: '無題のクエリ',
|
||||
sql: 'select 10;',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'main',
|
||||
}));
|
||||
});
|
||||
|
||||
it('keeps untitled fallback for database-scoped new query titles after a language switch', async () => {
|
||||
setCurrentLanguage('ja-JP');
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({ title: 'New query (main)', savedQueryId: 'saved-1' })} />);
|
||||
});
|
||||
|
||||
editorState.value = 'select 11;';
|
||||
|
||||
await act(async () => {
|
||||
await findButton(renderer!, '保存').props.onClick();
|
||||
});
|
||||
|
||||
expect(getQueryTabDraft('tab-1')).toBe('');
|
||||
});
|
||||
|
||||
@@ -8165,6 +8103,68 @@ describe('QueryEditor external SQL save', () => {
|
||||
});
|
||||
|
||||
expect(getQueryTabDraft('tab-1')).toBe('select 3;');
|
||||
});
|
||||
|
||||
it('keeps untitled fallback when the new query tab title is localized', async () => {
|
||||
setCurrentLanguage('en-US');
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({ title: 'New Query', savedQueryId: 'saved-1' })} />);
|
||||
});
|
||||
|
||||
editorState.value = 'select 8;';
|
||||
|
||||
await act(async () => {
|
||||
findButton(renderer!, 'Save').props.onClick();
|
||||
});
|
||||
|
||||
expect(storeState.saveQuery).toHaveBeenCalledWith(expect.objectContaining({
|
||||
id: 'saved-1',
|
||||
name: 'Untitled query',
|
||||
sql: 'select 8;',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'main',
|
||||
}));
|
||||
});
|
||||
|
||||
it('keeps untitled fallback after a language switch when the tab title came from another locale', async () => {
|
||||
setCurrentLanguage('ja-JP');
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({ title: 'New Query', savedQueryId: 'saved-1' })} />);
|
||||
});
|
||||
|
||||
editorState.value = 'select 10;';
|
||||
|
||||
await act(async () => {
|
||||
findButton(renderer!, '保存').props.onClick();
|
||||
});
|
||||
|
||||
expect(storeState.saveQuery).toHaveBeenCalledWith(expect.objectContaining({
|
||||
id: 'saved-1',
|
||||
name: '無題のクエリ',
|
||||
sql: 'select 10;',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'main',
|
||||
}));
|
||||
});
|
||||
|
||||
it('keeps untitled fallback for database-scoped new query titles after a language switch', async () => {
|
||||
setCurrentLanguage('ja-JP');
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({ title: 'New query (main)', savedQueryId: 'saved-1' })} />);
|
||||
});
|
||||
|
||||
editorState.value = 'select 11;';
|
||||
|
||||
await act(async () => {
|
||||
findButton(renderer!, '保存').props.onClick();
|
||||
});
|
||||
|
||||
expect(storeState.saveQuery).toHaveBeenCalledWith(expect.objectContaining({
|
||||
id: 'saved-1',
|
||||
name: '無題のクエリ',
|
||||
|
||||
@@ -1346,12 +1346,12 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
const toggleQueryResultsPanelActionRef = useRef<any>(null);
|
||||
const lastExternalQueryRef = useRef<string>(getTabQueryValue(tab));
|
||||
const lastLocalQueryRef = useRef<string>(query);
|
||||
const saveOperationQueueRef = useRef<Promise<unknown>>(Promise.resolve());
|
||||
const queryEditorMountedRef = useRef(true);
|
||||
const imeCompositionFallbackRef = useRef<{
|
||||
editor: any;
|
||||
valueBefore: string;
|
||||
selectionBefore: any;
|
||||
const saveOperationQueueRef = useRef<Promise<unknown>>(Promise.resolve());
|
||||
const queryEditorMountedRef = useRef(true);
|
||||
positionBefore: { lineNumber: number; column: number } | null;
|
||||
committedText: string;
|
||||
} | null>(null);
|
||||
@@ -1869,10 +1869,6 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
return savedQueries.find((item) => item.id === tabId) || null;
|
||||
}, [savedQueries, tab.id, tab.savedQueryId]);
|
||||
|
||||
const syncQueryDraft = useCallback((nextQuery: string) => {
|
||||
const next = String(nextQuery ?? '');
|
||||
lastLocalQueryRef.current = next;
|
||||
persistQueryTabDraftSnapshot(draftSnapshotTab, next, {
|
||||
useEffect(() => {
|
||||
queryEditorMountedRef.current = true;
|
||||
return () => {
|
||||
@@ -1889,6 +1885,10 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
return queued;
|
||||
}, []);
|
||||
|
||||
const syncQueryDraft = useCallback((nextQuery: string) => {
|
||||
const next = String(nextQuery ?? '');
|
||||
lastLocalQueryRef.current = next;
|
||||
persistQueryTabDraftSnapshot(draftSnapshotTab, next, {
|
||||
connectionId: currentConnectionIdRef.current,
|
||||
dbName: currentDbRef.current,
|
||||
});
|
||||
@@ -8238,6 +8238,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
|
||||
const persistQuery = async (payload: { id: string; name: string; createdAt?: number }): Promise<boolean> => {
|
||||
const sql = getCurrentQuery();
|
||||
lastLocalQueryRef.current = sql;
|
||||
const saved = {
|
||||
id: payload.id,
|
||||
name: payload.name,
|
||||
@@ -8284,7 +8285,6 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
|
||||
const openSaveQueryModal = (mode: 'save' | 'rename') => {
|
||||
setSaveModalMode(mode);
|
||||
lastLocalQueryRef.current = sql;
|
||||
saveForm.setFieldsValue({ name: currentSavedQuery?.name || resolveDefaultQueryName() });
|
||||
setIsSaveModalOpen(true);
|
||||
};
|
||||
@@ -8665,6 +8665,9 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
name: String(values.name || '').trim() || translate('query_editor.save_modal.unnamed'),
|
||||
createdAt: existed?.createdAt,
|
||||
});
|
||||
if (!applied) {
|
||||
return;
|
||||
}
|
||||
message.success(translate(
|
||||
saveModalMode === 'rename' ? 'query_editor.message.renamed' : 'query_editor.message.saved'
|
||||
));
|
||||
@@ -8688,9 +8691,6 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
currentResultSets,
|
||||
activeResultKeyRef.current,
|
||||
isV2Ui,
|
||||
if (!applied) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
const nextResultSets = currentResultSets.filter(result => result.key !== key);
|
||||
const nextActiveKey = currentActiveKey && currentActiveKey !== key
|
||||
|
||||
Reference in New Issue
Block a user