Skip to content

Commit 0472a06

Browse files
authored
fix(schema): prevent application from hanging when selecting ranges too fast on the "Schema" tab COMPASS-8048 (#5980)
fix(schema): debounce onChange calls to avoid application main thread locking
1 parent d39bd0c commit 0472a06

File tree

7 files changed

+43
-16
lines changed

7 files changed

+43
-16
lines changed

packages/compass-query-bar/src/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const QueryBarPlugin = registerHadronPlugin(
5959
}
6060
);
6161

62-
export type ChangeQueryBar = typeof useChangeQueryBarQuery;
62+
export type ChangeQueryFn = ReturnType<typeof useChangeQueryBarQuery>;
6363

6464
// Rendering query bar only makes sense if query bar store is in the rendering
6565
// tree. If it's not, `useQueryBarComponent` will return a `null` component

packages/compass-schema/src/components/coordinates-minichart/coordinates-minichart.jsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import GeoscatterMapItem from './marker';
1717
import { LIGHTMODE_TILE_URL, DARKMODE_TILE_URL } from './constants';
1818
import { getHereAttributionMessage } from './utils';
1919
import { debounce } from 'lodash';
20-
import { useChangeQueryBarQuery } from '@mongodb-js/compass-query-bar';
2120

2221
// TODO: Disable boxZoom handler for circle lasso.
2322
//
@@ -308,14 +307,13 @@ class UnthemedCoordinatesMinichart extends PureComponent {
308307
}
309308
}
310309

311-
const CoordinatesMinichart = ({ ...props }) => {
310+
const CoordinatesMinichart = ({ onQueryChanged, ...props }) => {
312311
const darkMode = useDarkMode();
313-
const changeQuery = useChangeQueryBarQuery();
314312
const onChange = useCallback(
315313
(geoQuery) => {
316-
changeQuery('mergeGeoQuery', geoQuery);
314+
onQueryChanged('mergeGeoQuery', geoQuery);
317315
},
318-
[changeQuery]
316+
[onQueryChanged]
319317
);
320318
return (
321319
<UnthemedCoordinatesMinichart
@@ -326,5 +324,9 @@ const CoordinatesMinichart = ({ ...props }) => {
326324
);
327325
};
328326

327+
CoordinatesMinichart.propTypes = {
328+
onQueryChanged: PropTypes.func,
329+
};
330+
329331
export default CoordinatesMinichart;
330332
export { CoordinatesMinichart };

packages/compass-schema/src/components/field.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useMemo, useState } from 'react';
1+
import React, { useEffect, useMemo, useState } from 'react';
22
import {
33
Subtitle,
44
Icon,
@@ -10,7 +10,7 @@ import {
1010
SignalPopover,
1111
PerformanceSignals,
1212
} from '@mongodb-js/compass-components';
13-
import { find } from 'lodash';
13+
import { debounce, find } from 'lodash';
1414
import { withPreferences } from 'compass-preferences-model/provider';
1515
import type {
1616
ArraySchemaType,
@@ -208,6 +208,22 @@ function Field({ actions, name, path, types, enableMaps }: FieldProps) {
208208
: undefined;
209209
});
210210

211+
// In some cases charts can call the change callback too often (for examlpe
212+
// when selecting from a very tightly rendered list of timeline items, like
213+
// ObjectIds), to avoid application hanging trying to process them all
214+
// syncronously and sequentially causing non-stop re-renders, we're debouncing
215+
// change call a bit and only applying the last selected change to the actual
216+
// query bar
217+
const debouncedChangeQuery = useMemo(() => {
218+
return debounce(changeQuery, 100);
219+
}, [changeQuery]);
220+
221+
useEffect(() => {
222+
return () => {
223+
debouncedChangeQuery.cancel();
224+
};
225+
}, [debouncedChangeQuery]);
226+
211227
const activeShownTypes = useMemo(() => sortTypes(types), [types]);
212228
const nestedDocType = useMemo(() => getNestedDocType(types), [types]);
213229

@@ -293,7 +309,7 @@ function Field({ actions, name, path, types, enableMaps }: FieldProps) {
293309
type={activeType}
294310
nestedDocType={nestedDocType}
295311
actions={actions}
296-
onQueryChanged={changeQuery}
312+
onQueryChanged={debouncedChangeQuery}
297313
/>
298314
</div>
299315
</div>

packages/compass-schema/src/components/minichart/minichart.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class MiniChart extends PureComponent {
8888
queryValue={fieldValue}
8989
type={this.props.type}
9090
width={width}
91+
onQueryChanged={this.props.onQueryChanged}
9192
/>
9293
);
9394
}
@@ -97,6 +98,7 @@ class MiniChart extends PureComponent {
9798
actions={this.props.actions}
9899
fieldName={fieldName}
99100
type={this.props.type}
101+
onQueryChanged={this.props.onQueryChanged}
100102
/>
101103
);
102104
}

packages/compass-schema/src/components/unique-minichart/unique-minichart.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class UniqueMiniChart extends Component {
1212
queryValue: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
1313
type: PropTypes.object.isRequired,
1414
width: PropTypes.number,
15+
onQueryChanged: PropTypes.func,
1516
};
1617

1718
constructor(props) {
@@ -46,6 +47,7 @@ class UniqueMiniChart extends Component {
4647
value={value}
4748
queryValue={this.props.queryValue}
4849
fieldName={this.props.fieldName}
50+
onQueryChanged={this.props.onQueryChanged}
4951
/>
5052
);
5153
});

packages/compass-schema/src/components/value-bubble.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
palette,
1010
useDarkMode,
1111
} from '@mongodb-js/compass-components';
12-
import { useChangeQueryBarQuery } from '@mongodb-js/compass-query-bar';
12+
import type { ChangeQueryFn } from '@mongodb-js/compass-query-bar';
1313

1414
import constants from '../constants/schema';
1515

@@ -63,21 +63,26 @@ type ValueBubbleProps = {
6363
fieldName: string;
6464
queryValue: any;
6565
value: any;
66+
onQueryChanged: ChangeQueryFn;
6667
};
6768

68-
function ValueBubble({ fieldName, queryValue, value }: ValueBubbleProps) {
69+
function ValueBubble({
70+
fieldName,
71+
queryValue,
72+
value,
73+
onQueryChanged,
74+
}: ValueBubbleProps) {
6975
const darkMode = useDarkMode();
70-
const changeQuery = useChangeQueryBarQuery();
7176

7277
const onBubbleClicked = useCallback(
7378
(e: React.MouseEvent<HTMLButtonElement>) => {
74-
changeQuery(e.shiftKey ? 'toggleDistinctValue' : 'setValue', {
79+
onQueryChanged(e.shiftKey ? 'toggleDistinctValue' : 'setValue', {
7580
field: fieldName,
7681
value,
7782
unsetIfSet: true,
7883
});
7984
},
80-
[changeQuery, fieldName, value]
85+
[onQueryChanged, fieldName, value]
8186
);
8287

8388
const extractedStringValue = useMemo(

packages/compass-schema/src/stores/store.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export type SchemaStore = StoreWithStateMixin<SchemaState> & {
105105
onDeleted: (geoQuery: ReturnType<typeof generateGeoQuery>) => void
106106
): void;
107107
stopAnalysis(): void;
108-
_trackSchemaAnalyzed(analysisTimeMS: number): void;
108+
_trackSchemaAnalyzed(analysisTimeMS: number, query: any): void;
109109
startAnalysis(): void;
110110
};
111111

@@ -317,7 +317,7 @@ export function activateSchemaPlugin(
317317
resultId: resultId(),
318318
});
319319

320-
this._trackSchemaAnalyzed(analysisTime);
320+
this._trackSchemaAnalyzed(analysisTime, query);
321321

322322
this.onSchemaSampled();
323323
} catch (err: any) {

0 commit comments

Comments
 (0)