mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-23 02:40:11 +00:00
fix(editor): preserve sql tab scroll position
This commit is contained in:
@@ -1124,6 +1124,10 @@ onUnmounted(() => {
|
||||
@editor-update="(tabId: string, v: string) => queryStore.updateSql(tabId, v)"
|
||||
@editor-selection-change="(v: string) => (selectedSql = v)"
|
||||
@editor-cursor-change="(p: number) => (cursorPos = p)"
|
||||
@editor-viewport-change="
|
||||
(tabId: string, viewport: { scrollTop: number; scrollLeft: number }) =>
|
||||
queryStore.updateEditorViewport(tabId, viewport)
|
||||
"
|
||||
@format-error="toast(t('toolbar.formatSqlFailed'))"
|
||||
@save-sql="void openSaveSqlDialog()"
|
||||
@reload="
|
||||
|
||||
@@ -104,6 +104,7 @@ const props = defineProps<{
|
||||
executionError?: string;
|
||||
readOnly?: boolean;
|
||||
forceWordWrap?: boolean;
|
||||
initialViewport?: { scrollTop: number; scrollLeft: number };
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -116,10 +117,12 @@ const emit = defineEmits<{
|
||||
clickTable: [tableName: string];
|
||||
clickColumn: [columns: Array<{ name: string; table: string; schema?: string }>, error?: string | undefined];
|
||||
closeColumnPanel: [];
|
||||
viewportChange: [viewport: { scrollTop: number; scrollLeft: number }];
|
||||
}>();
|
||||
|
||||
const editorRef = ref<HTMLDivElement>();
|
||||
const view = shallowRef<EditorViewType | null>(null);
|
||||
let viewportEmitFrame: number | null = null;
|
||||
const connectionStore = useConnectionStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const { isDark } = useTheme();
|
||||
@@ -1955,6 +1958,8 @@ onMounted(async () => {
|
||||
});
|
||||
|
||||
view.value = new EditorView({ state, parent: editorRef.value });
|
||||
view.value.scrollDOM.addEventListener("scroll", scheduleEditorViewportEmit, { passive: true });
|
||||
restoreEditorViewport();
|
||||
syncContextMenuState(view.value);
|
||||
syncEditorFontCssVars(liveFontSize.value, initialSettings.fontFamily);
|
||||
registerTableReferenceDropListener();
|
||||
@@ -2087,6 +2092,7 @@ watch(
|
||||
);
|
||||
|
||||
function pauseQueryEditorBackgroundWork() {
|
||||
if (view.value) emitEditorViewport(view.value);
|
||||
editorIsActive = false;
|
||||
semanticDiagnosticRunId++;
|
||||
if (semanticDiagnosticTimer) clearTimeout(semanticDiagnosticTimer);
|
||||
@@ -2099,6 +2105,7 @@ function resumeQueryEditorBackgroundWork() {
|
||||
editorIsActive = true;
|
||||
registerTableReferenceDropListener();
|
||||
scheduleSemanticDiagnostics();
|
||||
restoreEditorViewport();
|
||||
}
|
||||
|
||||
onActivated(resumeQueryEditorBackgroundWork);
|
||||
@@ -2107,10 +2114,42 @@ onDeactivated(pauseQueryEditorBackgroundWork);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
pauseQueryEditorBackgroundWork();
|
||||
if (viewportEmitFrame !== null) {
|
||||
cancelAnimationFrame(viewportEmitFrame);
|
||||
viewportEmitFrame = null;
|
||||
}
|
||||
view.value?.scrollDOM.removeEventListener("scroll", scheduleEditorViewportEmit);
|
||||
zoomCommitScheduler.dispose();
|
||||
view.value?.destroy();
|
||||
});
|
||||
|
||||
function emitEditorViewport(currentView: EditorViewType) {
|
||||
emit("viewportChange", {
|
||||
scrollTop: currentView.scrollDOM.scrollTop,
|
||||
scrollLeft: currentView.scrollDOM.scrollLeft,
|
||||
});
|
||||
}
|
||||
|
||||
function scheduleEditorViewportEmit() {
|
||||
if (viewportEmitFrame !== null) return;
|
||||
viewportEmitFrame = requestAnimationFrame(() => {
|
||||
viewportEmitFrame = null;
|
||||
if (view.value) emitEditorViewport(view.value);
|
||||
});
|
||||
}
|
||||
|
||||
function restoreEditorViewport() {
|
||||
const viewport = props.initialViewport;
|
||||
if (!view.value || !viewport) return;
|
||||
requestAnimationFrame(() => {
|
||||
if (!view.value) return;
|
||||
view.value.scrollDOM.scrollTo({
|
||||
top: viewport.scrollTop,
|
||||
left: viewport.scrollLeft,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openSearch(): boolean {
|
||||
return searchPanelRef.value?.openSearch() ?? false;
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ const emit = defineEmits<{
|
||||
editorUpdate: [tabId: string, value: string];
|
||||
editorSelectionChange: [value: string];
|
||||
editorCursorChange: [pos: number];
|
||||
editorViewportChange: [tabId: string, viewport: { scrollTop: number; scrollLeft: number }];
|
||||
formatError: [];
|
||||
reload: [sql?: string, searchText?: string, whereInput?: string, orderBy?: string, limit?: number, offset?: number];
|
||||
paginate: [offset: number, limit: number, whereInput?: string, orderBy?: string];
|
||||
@@ -445,9 +446,11 @@ defineExpose({ focusSearch, refreshData, handleModRTarget });
|
||||
:format-dialect="activeSqlFormatDialect"
|
||||
:format-request-id="formatSqlRequest?.tabId === activeTab.id ? formatSqlRequest.id : undefined"
|
||||
:execution-error="activeQueryError"
|
||||
:initial-viewport="activeTab.editorViewport"
|
||||
@update:model-value="emit('editorUpdate', activeTab.id, $event)"
|
||||
@selection-change="emit('editorSelectionChange', $event)"
|
||||
@cursor-change="emit('editorCursorChange', $event)"
|
||||
@viewport-change="emit('editorViewportChange', activeTab.id, $event)"
|
||||
@format-error="emit('formatError')"
|
||||
@execute="emit('execute')"
|
||||
@save="emit('saveSql')"
|
||||
|
||||
@@ -100,6 +100,7 @@ export function restoreOpenTabsState(
|
||||
isExecuting: false,
|
||||
isCancelling: false,
|
||||
queryExecutionStartedAt: undefined,
|
||||
editorViewport: undefined,
|
||||
isExplaining: false,
|
||||
resultEvicted: mode === "data" ? undefined : tab.resultEvicted,
|
||||
resultCacheKey: mode === "data" ? undefined : tab.resultCacheKey,
|
||||
|
||||
@@ -523,6 +523,12 @@ export const useQueryStore = defineStore("query", () => {
|
||||
}
|
||||
}
|
||||
|
||||
function updateEditorViewport(id: string, viewport: { scrollTop: number; scrollLeft: number }) {
|
||||
const tab = tabs.value.find((t) => t.id === id);
|
||||
if (!tab) return;
|
||||
tab.editorViewport = viewport;
|
||||
}
|
||||
|
||||
function renameTab(id: string, title: string) {
|
||||
const trimmed = title.trim();
|
||||
if (!trimmed) return false;
|
||||
@@ -1746,6 +1752,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
releaseConnectionTabs,
|
||||
releaseDatabaseTabs,
|
||||
updateSql,
|
||||
updateEditorViewport,
|
||||
renameTab,
|
||||
openObjectBrowser,
|
||||
openUserAdmin,
|
||||
|
||||
@@ -396,6 +396,10 @@ export interface QueryTab {
|
||||
isExecuting: boolean;
|
||||
isCancelling?: boolean;
|
||||
queryExecutionStartedAt?: number;
|
||||
editorViewport?: {
|
||||
scrollTop: number;
|
||||
scrollLeft: number;
|
||||
};
|
||||
executionId?: string;
|
||||
isExplaining?: boolean;
|
||||
explainExecutionId?: string;
|
||||
|
||||
Reference in New Issue
Block a user