Skip to content

Commit 649077e

Browse files
committed
[5726] Virtualize search results list to improve performance
Bug: #5726 Signed-off-by: Pierre-Charles David <[email protected]>
1 parent 92966e8 commit 649077e

File tree

12 files changed

+99
-170
lines changed

12 files changed

+99
-170
lines changed

CHANGELOG.adoc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ This mechanisms was previously used to provide the menu entry to update/remove a
108108
- [releng] Switch to AQL 8.1.0 from https://download.eclipse.org/acceleo/updates/releases/4.2/R202510230846/[Acceleo 4.2.0].
109109
This also includes an update from ANTLR 4.10.1 to 4.13.2.
110110
- https://github.com/eclipse-sirius/sirius-web/issues/5653[#5653] Add a dependency to `spring-boot-starter-data-elasticsearch` in `sirius-web-infrastructure`
111-
111+
- [releng] Switch to react-window 2.2.2.
112112

113113
=== Bug fixes
114114

@@ -195,8 +195,7 @@ This will allow to integrate the command palette in other contexts than the work
195195
As a result, some of those menu items are not contributed anymore on invalid use cases such as being able to create a new object in a read only library.
196196
- https://github.com/eclipse-sirius/sirius-web/issues/5702[#5702] [table] Improve the rendering of components used in table cells
197197
- https://github.com/eclipse-sirius/sirius-web/issues/5788[#5788] [sirius-web] Add resource changes in the impact analysis tree.
198-
199-
198+
- https://github.com/eclipse-sirius/sirius-web/issues/5726[#5726] [sirius-web] Virtualize the display of search results to improve performance on large result sets
200199

201200

202201
== 2025.10.0

package-lock.json

Lines changed: 12 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/sirius-web/frontend/sirius-web-application/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
"react-dom": "18.3.1",
7474
"react-i18next": "16.2.3",
7575
"react-router-dom": "6.26.0",
76-
"react-window": "1.8.11",
76+
"react-window": "2.2.2",
7777
"@xyflow/react": "12.6.0",
7878
"tss-react": "4.9.16",
7979
"react-resizable-panels": "3.0.2"
@@ -129,7 +129,7 @@
129129
"react-dom": "18.3.1",
130130
"react-i18next": "16.2.3",
131131
"react-router-dom": "6.26.0",
132-
"react-window": "1.8.11",
132+
"react-window": "2.2.2",
133133
"rollup-plugin-peer-deps-external": "2.2.4",
134134
"react-resizable-panels": "3.0.2",
135135
"typescript": "5.4.5",

packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/query/QueryView.tsx

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import {
4343
useRef,
4444
useState,
4545
} from 'react';
46-
import { FixedSizeList, ListChildComponentProps } from 'react-window';
46+
import { List as FixedSizeList, RowComponentProps } from 'react-window';
4747
import { makeStyles } from 'tss-react/mui';
4848
import { useCurrentProject } from '../../useCurrentProject';
4949
import { SynchronizationButton } from '../SynchronizationButton';
@@ -60,14 +60,14 @@ import { useEvaluateExpression } from './useEvaluateExpression';
6060
import {
6161
GQLBooleanExpressionResult,
6262
GQLIntExpressionResult,
63+
GQLObject,
6364
GQLObjectExpressionResult,
6465
GQLObjectsExpressionResult,
6566
GQLStringExpressionResult,
6667
GQLStringsExpressionResult,
6768
} from './useEvaluateExpression.types';
6869
import { useExpression } from './useExpression';
6970
import { useQueryViewHandle } from './useQueryViewHandle';
70-
import { useResultAreaSize } from './useResultAreaSize';
7171

7272
const useQueryViewStyles = makeStyles()((theme) => ({
7373
view: {
@@ -92,6 +92,9 @@ const useQueryViewStyles = makeStyles()((theme) => ({
9292
},
9393
content: {
9494
overflow: 'auto',
95+
display: 'grid',
96+
gridTemplateColumns: '1fr',
97+
gridTemplateRows: '1fr',
9598
},
9699
}));
97100

@@ -105,6 +108,7 @@ export const QueryView = forwardRef<WorkbenchViewHandle, WorkbenchViewComponentP
105108
flexDirection: 'column',
106109
gap: theme.spacing(2),
107110
paddingX: theme.spacing(1),
111+
overflow: 'auto',
108112
});
109113

110114
const [state, setState] = useState<QueryViewState>({
@@ -134,8 +138,6 @@ export const QueryView = forwardRef<WorkbenchViewHandle, WorkbenchViewComponentP
134138
const { evaluateExpression, loading, result } = useEvaluateExpression(state.objectIds);
135139
const handleEvaluateExpression = (expression: string) => evaluateExpression(editingContextId, expression);
136140

137-
const { ref: resultAreaRef, width, height } = useResultAreaSize();
138-
139141
const initialQueryViewConfiguration: QueryViewConfiguration =
140142
initialConfiguration as unknown as QueryViewConfiguration;
141143
const initialQueryText = initialQueryViewConfiguration?.queryText ?? null;
@@ -148,15 +150,15 @@ export const QueryView = forwardRef<WorkbenchViewHandle, WorkbenchViewComponentP
148150
);
149151

150152
const contents: JSX.Element = (
151-
<Box data-representation-kind="query" sx={queryViewStyle} ref={resultAreaRef}>
153+
<Box data-representation-kind="query" sx={queryViewStyle}>
152154
<ExpressionArea
153155
editingContextId={editingContextId}
154156
initialQueryText={initialQueryText}
155157
onEvaluateExpression={handleEvaluateExpression}
156158
disabled={loading || readOnly}
157159
ref={expressionAreaRef}
158160
/>
159-
<ResultArea loading={loading} payload={result} width={width} height={height} />
161+
<ResultArea loading={loading} payload={result} />
160162
</Box>
161163
);
162164
return (
@@ -254,11 +256,11 @@ const ObjectExpressionResultViewer = ({ result }: ExpressionResultViewerProps) =
254256
minWidth: '0px',
255257
});
256258
return (
257-
<Box>
259+
<Box sx={{ overflow: 'auto' }}>
258260
<Typography variant="body2" gutterBottom>
259261
One object has been returned
260262
</Typography>
261-
<Box sx={(theme) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(1) })}>
263+
<Box sx={(theme) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(1), overflow: 'auto' })}>
262264
<List dense>
263265
<ListItem sx={listItemStyle}>
264266
<ListItemIcon sx={listItemIconStyle}>
@@ -275,7 +277,7 @@ const ObjectExpressionResultViewer = ({ result }: ExpressionResultViewerProps) =
275277
);
276278
};
277279

278-
const ObjectRow = ({ data, index, style }: ListChildComponentProps) => {
280+
const ObjectRow = ({ data, index, style }: RowComponentProps<{ data: GQLObject[] }>) => {
279281
const listItemStyle: SxProps<Theme> = (theme) => ({
280282
gap: theme.spacing(2),
281283
});
@@ -295,7 +297,7 @@ const ObjectRow = ({ data, index, style }: ListChildComponentProps) => {
295297
);
296298
};
297299

298-
const ObjectsExpressionResultViewer = ({ result, width, height }: ExpressionResultViewerProps) => {
300+
const ObjectsExpressionResultViewer = ({ result }: ExpressionResultViewerProps) => {
299301
if (result.__typename !== 'ObjectsExpressionResult') {
300302
return null;
301303
}
@@ -305,23 +307,22 @@ const ObjectsExpressionResultViewer = ({ result, width, height }: ExpressionResu
305307
const listStyle: SxProps<Theme> = (theme) => ({
306308
border: `1px solid ${theme.palette.divider}`,
307309
marginBottom: '1px',
310+
overflow: 'auto',
308311
});
309312

310313
return (
311-
<Box>
314+
<Box sx={{ overflow: 'auto' }}>
312315
<Typography variant="body2" gutterBottom>
313316
A collection of {objectsValue.length} object{objectsValue.length > 1 ? 's' : ''} has been returned
314317
</Typography>
315-
<Box sx={(theme) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(1) })}>
318+
<Box sx={(theme) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(1), overflow: 'auto' })}>
316319
<List dense disablePadding sx={listStyle}>
317320
<FixedSizeList
318-
height={height}
319-
width={width}
320-
itemData={objectsValue}
321-
itemCount={objectsValue.length}
322-
itemSize={34}>
323-
{ObjectRow}
324-
</FixedSizeList>
321+
rowComponent={ObjectRow}
322+
rowProps={{ data: objectsValue }}
323+
rowCount={objectsValue.length}
324+
rowHeight={34}
325+
/>
325326
</List>
326327
<Box sx={{ display: 'flex', flexDirection: 'row' }}>
327328
<ExportResultButton objectIds={objectsValue.map((objectValue) => objectValue.id)} />
@@ -351,7 +352,7 @@ const BooleanExpressionResultViewer = ({ result }: ExpressionResultViewerProps)
351352
);
352353
};
353354

354-
const StringRow = ({ data, index, style }: ListChildComponentProps) => {
355+
const StringRow = ({ data, index, style }: RowComponentProps<{ data: string[] }>) => {
355356
const listItemStyle: SxProps<Theme> = (theme) => ({
356357
gap: theme.spacing(2),
357358
});
@@ -365,7 +366,7 @@ const StringRow = ({ data, index, style }: ListChildComponentProps) => {
365366
);
366367
};
367368

368-
const StringsExpressionResultViewer = ({ result, width, height }: ExpressionResultViewerProps) => {
369+
const StringsExpressionResultViewer = ({ result }: ExpressionResultViewerProps) => {
369370
if (result.__typename !== 'StringsExpressionResult') {
370371
return null;
371372
}
@@ -383,13 +384,11 @@ const StringsExpressionResultViewer = ({ result, width, height }: ExpressionResu
383384
</Typography>
384385
<List dense disablePadding sx={listStyle}>
385386
<FixedSizeList
386-
height={height}
387-
width={width}
388-
itemData={stringsValue}
389-
itemCount={stringsValue.length}
390-
itemSize={34}>
391-
{StringRow}
392-
</FixedSizeList>
387+
rowComponent={StringRow}
388+
rowProps={{ data: stringsValue }}
389+
rowCount={stringsValue.length}
390+
rowHeight={34}
391+
/>
393392
</List>
394393
</Box>
395394
);
@@ -484,12 +483,13 @@ const LoadingViewer = () => {
484483
);
485484
};
486485

487-
const ResultArea = ({ loading, payload, width, height }: ResultAreaProps) => {
486+
const ResultArea = ({ loading, payload }: ResultAreaProps) => {
488487
const resultAreaToolbarStyle: SxProps<Theme> = {
489488
display: 'flex',
490489
flexDirection: 'row',
491490
alignItems: 'center',
492491
justifyContent: 'space-between',
492+
overflow: 'auto',
493493
};
494494

495495
const titleAreaStyle: SxProps<Theme> = {
@@ -503,14 +503,14 @@ const ResultArea = ({ loading, payload, width, height }: ResultAreaProps) => {
503503
} else if (payload) {
504504
const Viewer = resultType2viewer[payload.result.__typename];
505505
if (Viewer) {
506-
content = <Viewer result={payload.result} width={width} height={height} />;
506+
content = <Viewer result={payload.result} />;
507507
} else {
508508
content = <Typography variant="body2">The expression has returned a result that is not supported</Typography>;
509509
}
510510
}
511511

512512
return (
513-
<div data-role="result">
513+
<div data-role="result" style={{ overflow: 'auto' }}>
514514
<Box sx={resultAreaToolbarStyle}>
515515
<Box sx={titleAreaStyle}>
516516
<Typography variant="subtitle2">Evaluation result</Typography>

packages/sirius-web/frontend/sirius-web-application/src/views/edit-project/workbench-views/query/QueryView.types.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,10 @@ export interface ExpressionAreaHandle {
3636
export interface ResultAreaProps {
3737
loading: boolean;
3838
payload: GQLEvaluateExpressionSuccessPayload | null;
39-
height: number | null;
40-
width: number | null;
4139
}
4240

4341
export interface ExpressionResultViewerProps {
4442
result: GQLExpressionResult;
45-
height: number | null;
46-
width: number | null;
4743
}
4844

4945
export interface ExportResultButtonProps {

0 commit comments

Comments
 (0)