Skip to content

Commit fe4b819

Browse files
author
root
committed
fix(ui): guard explorer selectors on slow networks
Disable selector buttons until options are loaded to prevent error state on slow networks.\n\nCloses #1574.
1 parent 6e098e3 commit fe4b819

3 files changed

Lines changed: 90 additions & 35 deletions

File tree

aim/web/ui/src/pages/ImagesExplore/components/SelectForm/SelectForm.tsx

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ function SelectForm({
4747
const autocompleteRef: any = React.useRef<React.MutableRefObject<any>>(null);
4848
const advancedAutocompleteRef: any =
4949
React.useRef<React.MutableRefObject<any>>(null);
50+
51+
// Guard against the user opening the selector before options are loaded (slow network).
52+
const isSelectDataReady = Array.isArray(selectFormData?.options);
53+
const isImagesSelectorDisabled = isDisabled || !isSelectDataReady;
5054
React.useEffect(() => {
5155
return () => {
5256
searchMetricsRef.current?.abort();
@@ -115,6 +119,9 @@ function SelectForm({
115119
}
116120

117121
function handleClick(event: React.ChangeEvent<any>) {
122+
if (isImagesSelectorDisabled) {
123+
return;
124+
}
118125
setAnchorEl(event.currentTarget);
119126
}
120127

@@ -167,7 +174,7 @@ function SelectForm({
167174
<AutocompleteInput
168175
advanced
169176
refObject={advancedAutocompleteRef}
170-
context={selectFormData?.advancedSuggestions}
177+
context={selectFormData?.advancedSuggestions ?? {}}
171178
value={selectedImagesData?.advancedQuery}
172179
error={selectFormData?.advancedError}
173180
onEnter={handleSearch}
@@ -177,16 +184,26 @@ function SelectForm({
177184
) : (
178185
<ErrorBoundary>
179186
<Box display='flex' alignItems='center'>
180-
<Button
181-
variant='contained'
182-
color='primary'
183-
onClick={handleClick}
184-
aria-describedby={id}
185-
disabled={isDisabled}
187+
<Tooltip
188+
title={
189+
isImagesSelectorDisabled && !isDisabled
190+
? 'Loading…'
191+
: ''
192+
}
186193
>
187-
<Icon name='plus' style={{ marginRight: '0.5rem' }} />
188-
Images
189-
</Button>
194+
<div>
195+
<Button
196+
variant='contained'
197+
color='primary'
198+
onClick={handleClick}
199+
aria-describedby={id}
200+
disabled={isImagesSelectorDisabled}
201+
>
202+
<Icon name='plus' style={{ marginRight: '0.5rem' }} />
203+
Images
204+
</Button>
205+
</div>
206+
</Tooltip>
190207
<Popper
191208
id={id}
192209
open={open}
@@ -304,7 +321,7 @@ function SelectForm({
304321
<div className='SelectForm__TextField'>
305322
<AutocompleteInput
306323
refObject={autocompleteRef}
307-
context={selectFormData?.suggestions}
324+
context={selectFormData?.suggestions ?? {}}
308325
value={selectedImagesData?.query}
309326
error={selectFormData?.error}
310327
onEnter={handleSearch}

aim/web/ui/src/pages/Metrics/components/SelectForm/SelectForm.tsx

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ function SelectForm({
4646
const autocompleteRef: any = React.useRef<React.MutableRefObject<any>>(null);
4747
const advancedAutocompleteRef: any =
4848
React.useRef<React.MutableRefObject<any>>(null);
49+
50+
// On slow networks it's possible for the user to click the selector before
51+
// the explorer context/options are loaded. Guard against that state.
52+
const isSelectDataReady = Array.isArray(selectFormData?.options);
53+
const isMetricSelectorDisabled = isDisabled || !isSelectDataReady;
4954
React.useEffect(() => {
5055
return () => {
5156
searchRef.current?.abort();
@@ -106,6 +111,9 @@ function SelectForm({
106111
}
107112

108113
function handleClick(event: React.ChangeEvent<any>) {
114+
if (isMetricSelectorDisabled) {
115+
return;
116+
}
109117
setAnchorEl(event.currentTarget);
110118
}
111119

@@ -156,9 +164,9 @@ function SelectForm({
156164
<div className='Metrics__SelectForm__textarea'>
157165
<AutocompleteInput
158166
advanced
159-
error={selectFormData.advancedError}
167+
error={selectFormData?.advancedError}
160168
refObject={advancedAutocompleteRef}
161-
context={selectFormData?.advancedSuggestions}
169+
context={selectFormData?.advancedSuggestions ?? {}}
162170
value={selectedMetricsData?.advancedQuery}
163171
onEnter={handleMetricSearch}
164172
disabled={isDisabled}
@@ -167,16 +175,24 @@ function SelectForm({
167175
) : (
168176
<>
169177
<Box display='flex' alignItems='center'>
170-
<Button
171-
variant='contained'
172-
color='primary'
173-
onClick={handleClick}
174-
aria-describedby={id}
175-
disabled={isDisabled}
178+
<Tooltip
179+
title={
180+
isMetricSelectorDisabled && !isDisabled ? 'Loading…' : ''
181+
}
176182
>
177-
<Icon name='plus' style={{ marginRight: '0.5rem' }} />
178-
Metrics
179-
</Button>
183+
<div>
184+
<Button
185+
variant='contained'
186+
color='primary'
187+
onClick={handleClick}
188+
aria-describedby={id}
189+
disabled={isMetricSelectorDisabled}
190+
>
191+
<Icon name='plus' style={{ marginRight: '0.5rem' }} />
192+
Metrics
193+
</Button>
194+
</div>
195+
</Tooltip>
180196
<Popper
181197
id={id}
182198
open={open}
@@ -292,9 +308,9 @@ function SelectForm({
292308
<div className='Metrics__SelectForm__TextField'>
293309
<AutocompleteInput
294310
refObject={autocompleteRef}
295-
error={selectFormData.error}
311+
error={selectFormData?.error}
296312
value={selectedMetricsData?.query}
297-
context={selectFormData.suggestions}
313+
context={selectFormData?.suggestions ?? {}}
298314
onEnter={handleMetricSearch}
299315
disabled={isDisabled}
300316
/>

aim/web/ui/src/pages/Params/components/SelectForm/SelectForm.tsx

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import React from 'react';
22
import classNames from 'classnames';
33

4-
import { Box, Checkbox, Divider, InputBase, Popper } from '@material-ui/core';
4+
import {
5+
Box,
6+
Checkbox,
7+
Divider,
8+
InputBase,
9+
Popper,
10+
Tooltip,
11+
} from '@material-ui/core';
512
import Autocomplete from '@material-ui/lab/Autocomplete';
613
import {
714
CheckBox as CheckBoxIcon,
@@ -34,6 +41,10 @@ function SelectForm({
3441
const [searchValue, setSearchValue] = React.useState<string>('');
3542
const searchRef = React.useRef<any>(null);
3643
const autocompleteRef: any = React.useRef<React.MutableRefObject<any>>(null);
44+
45+
// Guard against the user opening the selector before options are loaded (slow network).
46+
const isSelectDataReady = Array.isArray(selectFormData?.options);
47+
const isParamsSelectorDisabled = isDisabled || !isSelectDataReady;
3748
React.useEffect(() => {
3849
return () => {
3950
searchRef.current?.abort();
@@ -86,6 +97,9 @@ function SelectForm({
8697
}
8798

8899
function handleClick(event: React.ChangeEvent<any>) {
100+
if (isParamsSelectorDisabled) {
101+
return;
102+
}
89103
setAnchorEl(event.currentTarget);
90104
}
91105

@@ -131,16 +145,24 @@ function SelectForm({
131145
>
132146
<ErrorBoundary>
133147
<Box display='flex' alignItems='center'>
134-
<Button
135-
variant='contained'
136-
color='primary'
137-
onClick={handleClick}
138-
aria-describedby={id}
139-
disabled={isDisabled}
148+
<Tooltip
149+
title={
150+
isParamsSelectorDisabled && !isDisabled ? 'Loading…' : ''
151+
}
140152
>
141-
<Icon name='plus' style={{ marginRight: '0.5rem' }} /> Run
142-
Params
143-
</Button>
153+
<div>
154+
<Button
155+
variant='contained'
156+
color='primary'
157+
onClick={handleClick}
158+
aria-describedby={id}
159+
disabled={isParamsSelectorDisabled}
160+
>
161+
<Icon name='plus' style={{ marginRight: '0.5rem' }} />
162+
Run Params
163+
</Button>
164+
</div>
165+
</Tooltip>
144166
<Popper
145167
id={id}
146168
open={open}
@@ -278,7 +300,7 @@ function SelectForm({
278300
<div className='SelectForm__TextField'>
279301
<AutocompleteInput
280302
refObject={autocompleteRef}
281-
context={selectFormData?.suggestions}
303+
context={selectFormData?.suggestions ?? {}}
282304
error={selectFormData?.error}
283305
onEnter={handleParamsSearch}
284306
value={selectedParamsData?.query}

0 commit comments

Comments
 (0)