mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
[CB] application freezes during loading on heavy resultsets (ORIGINAL FIX) (#3717)
* dbeaver/pro#6731 enables virtualization always * removes default virtualization prop * [CB] application freezes during loading on heavy resultsets (OPTIONAL FIXES) (#3715) * dbeaver/pro#6731 adds some optimizations * cleanup * pr fixes * cleanup * removes optimizations * linter fixes
This commit is contained in:
@@ -1,5 +1,20 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||
import { DataGrid as DataGridBase, type ColumnOrColumnGroup, type CellSelectArgs, type DataGridHandle, type ColumnWidth, type ColumnWidths } from 'react-data-grid';
|
||||
import {
|
||||
DataGrid as DataGridBase,
|
||||
type ColumnOrColumnGroup,
|
||||
type CellSelectArgs,
|
||||
type DataGridHandle,
|
||||
type ColumnWidth,
|
||||
type ColumnWidths,
|
||||
} from 'react-data-grid';
|
||||
import { rowRenderer } from './renderers/rowRenderer.js';
|
||||
import { cellRenderer } from './renderers/cellRenderer.js';
|
||||
import { DataGridCellHeaderContext, type IDataGridHeaderCellContext } from './DataGridHeaderCellContext.js';
|
||||
@@ -111,9 +126,12 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
|
||||
innerGridRef.current?.scrollToCell({ idx: position.colIdx && dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx });
|
||||
},
|
||||
openEditor: (position: ICellPosition) => {
|
||||
innerGridRef.current?.selectCell({ idx: dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx }, {
|
||||
enableEditor: true,
|
||||
});
|
||||
innerGridRef.current?.selectCell(
|
||||
{ idx: dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx },
|
||||
{
|
||||
enableEditor: true,
|
||||
},
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -126,7 +144,7 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
|
||||
}
|
||||
}
|
||||
|
||||
let rows = useMemo(
|
||||
const rows = useMemo(
|
||||
() =>
|
||||
new Array<IInnerRow>(rowsCount).fill({ idx: 0 }).map((_, i) => ({
|
||||
idx: i,
|
||||
@@ -142,21 +160,16 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
|
||||
onCellKeyDown?.({ colIdx: dndHeaderContext.getDataColIdx(args.column.idx), rowIdx: args.rowIdx }, event);
|
||||
}
|
||||
|
||||
const isMeasurementRender = columnWidths.size === 0 && columnCount.get() > 0;
|
||||
|
||||
if (isMeasurementRender) {
|
||||
rows = rows.slice(0, 100);
|
||||
}
|
||||
|
||||
return (
|
||||
<HeaderDnDContext value={dndHeaderContext}>
|
||||
<DataGridRowContext value={{ rowCount, onScrollToBottom }}>
|
||||
<DataGridCellContext value={{ cell, cellText, cellElement, cellTooltip, onCellChange }}>
|
||||
<DataGridCellHeaderContext value={{ headerElement, headerText, getHeaderDnD, columnSortable, onColumnSort, columnSortingState, onHeaderKeyDown }}>
|
||||
<DataGridCellHeaderContext
|
||||
value={{ headerElement, headerText, getHeaderDnD, columnSortable, onColumnSort, columnSortingState, onHeaderKeyDown }}
|
||||
>
|
||||
<DataGridBase
|
||||
ref={innerGridRef}
|
||||
columns={dndHeaderContext.columns}
|
||||
enableVirtualization={!isMeasurementRender}
|
||||
rows={rows}
|
||||
className={className}
|
||||
headerRowHeight={getHeaderHeight?.()}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -71,14 +71,14 @@ export class LocalizationService extends Bootstrap {
|
||||
this.localeProviders.push(provider);
|
||||
}
|
||||
|
||||
setSupportedLanguages(locales: ILocale[]) {
|
||||
setSupportedLanguages(locales: ILocale[]): void {
|
||||
this.supportedLanguages = locales;
|
||||
if (this.supportedLanguages.length === 0) {
|
||||
this.supportedLanguages = [DEFAULT_LOCALE];
|
||||
}
|
||||
}
|
||||
|
||||
setLanguage(lang: string) {
|
||||
setLanguage(lang: string): void {
|
||||
this.language = lang;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,6 @@ export class LocalizationService extends Bootstrap {
|
||||
name: 'Vietnamese',
|
||||
nativeName: 'Tiếng Việt',
|
||||
},
|
||||
|
||||
]);
|
||||
this.addProvider(this.coreProvider.bind(this));
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ export class ResultSetViewAction extends DatabaseDataAction<any, IDatabaseResult
|
||||
}
|
||||
|
||||
get columnKeys(): IResultSetColumnKey[] {
|
||||
return this.columns.map(c => ({ index: this.data.columns.indexOf(c) }));
|
||||
return this.columnsOrder.map(index => ({ index }));
|
||||
}
|
||||
|
||||
get rows(): IResultSetValue[][] {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -197,7 +197,7 @@ export const TableViewer = observer<TableViewerProps, HTMLDivElement>(
|
||||
|
||||
const isStatistics = result?.loadedFully && !result.data;
|
||||
const resultExist = dataModel.source.hasResult(resultIndex);
|
||||
const overlay = dataModel.source.results.length > 0 && presentation.dataFormat === dataFormat;
|
||||
const overlay = getComputed(() => dataModel.source.results.length > 0 && presentation.dataFormat === dataFormat);
|
||||
const valuePanelDisplayed =
|
||||
valuePresentation &&
|
||||
(valuePresentation.dataFormat === undefined || valuePresentation.dataFormat === dataFormat) &&
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,9 +15,9 @@ export function navigationTreeDuplicateFilter(navNodeViewService: NavNodeViewSer
|
||||
const { nodes, duplicates } = navNodeViewService.filterDuplicates(children);
|
||||
|
||||
untracked(() => {
|
||||
navNodeViewService.logDuplicates(node.id, duplicates);
|
||||
navNodeViewService.logDuplicates(node.id, Array.from(duplicates));
|
||||
});
|
||||
|
||||
return nodes;
|
||||
return Array.from(nodes);
|
||||
};
|
||||
}
|
||||
|
||||
+14
-15
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,8 +13,8 @@ import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import type { INavNodeFolderTransform, NavNodeFolderTransformFn, NavNodeTransformView } from './IFolderTransform.js';
|
||||
|
||||
export interface INodeDuplicateList {
|
||||
nodes: string[];
|
||||
duplicates: string[];
|
||||
nodes: Set<string>;
|
||||
duplicates: Set<string>;
|
||||
}
|
||||
|
||||
export interface INodeLimitedList {
|
||||
@@ -59,10 +59,10 @@ export class NavNodeViewService {
|
||||
const { nodes, duplicates } = this.filterDuplicates(children);
|
||||
|
||||
untracked(() => {
|
||||
this.logDuplicates(nodeId, duplicates);
|
||||
this.logDuplicates(nodeId, Array.from(duplicates));
|
||||
});
|
||||
|
||||
return nodes;
|
||||
return Array.from(nodes);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -80,25 +80,24 @@ export class NavNodeViewService {
|
||||
}
|
||||
|
||||
filterDuplicates(nodes: string[]): INodeDuplicateList {
|
||||
const seen = new Set<string>();
|
||||
const duplicatesSet = new Set<string>();
|
||||
const nextChildren: string[] = [];
|
||||
const duplicates: string[] = [];
|
||||
|
||||
for (const child of nodes) {
|
||||
const isDuplicate = duplicates.includes(child);
|
||||
|
||||
if (nextChildren.includes(child) || isDuplicate) {
|
||||
if (!isDuplicate) {
|
||||
duplicates.push(child);
|
||||
nextChildren.splice(nextChildren.indexOf(child), 1);
|
||||
}
|
||||
if (seen.has(child)) {
|
||||
duplicatesSet.add(child);
|
||||
} else {
|
||||
seen.add(child);
|
||||
nextChildren.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueChildren = new Set(nextChildren.filter(child => !duplicatesSet.has(child)));
|
||||
|
||||
return {
|
||||
nodes: nextChildren,
|
||||
duplicates,
|
||||
nodes: uniqueChildren,
|
||||
duplicates: duplicatesSet,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -35,12 +35,10 @@ export const VirtualFolderPanel: NavNodeTransformViewComponent = observer(functi
|
||||
const allData = dbObjectLoader.resource.get(pagination.allPages).filter(isDefined);
|
||||
const { nodes, duplicates } = navNodeViewService.filterDuplicates(allData.map(node => node?.id) || []);
|
||||
|
||||
const objects = allData.filter(
|
||||
object => object && nodes.includes(object.id) && navNodeInfoResource.get(object.id)?.nodeType === nodeType,
|
||||
) as DBObject[];
|
||||
const objects = allData.filter(object => object && nodes.has(object.id) && navNodeInfoResource.get(object.id)?.nodeType === nodeType) as DBObject[];
|
||||
|
||||
useEffect(() => {
|
||||
navNodeViewService.logDuplicates(nodeId, duplicates);
|
||||
navNodeViewService.logDuplicates(nodeId, Array.from(duplicates));
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
+3
-3
@@ -38,15 +38,15 @@ export const ObjectPropertyTable = observer<ObjectPropertyTableProps>(function O
|
||||
const allData = dbObjectLoader.resource.get(pagination.allPages).filter(isDefined);
|
||||
const { nodes, duplicates } = navNodeViewService.filterDuplicates(allData.map(node => node?.id) || []);
|
||||
|
||||
const objects = allData.filter(node => nodes.includes(node.id)) as DBObject[];
|
||||
const objects = allData.filter(node => nodes.has(node.id)) as DBObject[];
|
||||
|
||||
useEffect(() => {
|
||||
navNodeViewService.logDuplicates(objectId, duplicates);
|
||||
navNodeViewService.logDuplicates(objectId, Array.from(duplicates));
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{nodes.length === 0 ? (
|
||||
{nodes.size === 0 ? (
|
||||
<TextPlaceholder>{translate('plugin_object_viewer_table_no_items')}</TextPlaceholder>
|
||||
) : (
|
||||
<div className={s(styles, { box: true }, className)}>
|
||||
|
||||
Reference in New Issue
Block a user