|
1 | 1 | import { isModelFeatureFlag, ModelFeatureFlag, useResolvedExtensions } from '@openshift-console/dynamic-plugin-sdk'; |
2 | 2 | import { |
| 3 | + Alert, |
| 4 | + AlertActionCloseButton, |
3 | 5 | Button, |
4 | 6 | Drawer, |
5 | 7 | DrawerContent, |
@@ -45,7 +47,7 @@ import { DefaultOptions, TopologyGroupTypes, TopologyOptions } from '../model/to |
45 | 47 | import { Column, getDefaultColumns } from '../utils/columns'; |
46 | 48 | import { TimeRange } from '../utils/datetime'; |
47 | 49 | import { getHTTPErrorDetails } from '../utils/errors'; |
48 | | -import { DisabledFilters, Filter, getDisabledFiltersRecord, getEnabledFilters } from '../model/filters'; |
| 50 | +import { DisabledFilters, Filter, hasIndexFields, getDisabledFiltersRecord, getEnabledFilters } from '../model/filters'; |
49 | 51 | import { |
50 | 52 | LOCAL_STORAGE_COLS_KEY, |
51 | 53 | LOCAL_STORAGE_DISABLED_FILTERS_KEY, |
@@ -119,6 +121,8 @@ export const NetflowTraffic: React.FC<{ |
119 | 121 | setURLParams(queryParams); |
120 | 122 | } |
121 | 123 |
|
| 124 | + const warningTimeOut = React.useRef<NodeJS.Timeout | undefined>(); |
| 125 | + const [warningMessage, setWarningMessage] = React.useState<string | undefined>(); |
122 | 126 | const [isOverflowMenuOpen, setOverflowMenuOpen] = React.useState(false); |
123 | 127 | const [isFullScreen, setFullScreen] = React.useState(false); |
124 | 128 | const [loading, setLoading] = React.useState(true); |
@@ -240,45 +244,67 @@ export const NetflowTraffic: React.FC<{ |
240 | 244 | topologyOptions.groupTypes |
241 | 245 | ]); |
242 | 246 |
|
| 247 | + const manageWarnings = React.useCallback( |
| 248 | + (query: Promise<unknown>) => { |
| 249 | + Promise.race([query, new Promise((resolve, reject) => setTimeout(reject, 2000, 'slow'))]).then( |
| 250 | + null, |
| 251 | + (reason: string) => { |
| 252 | + if (reason === 'slow') { |
| 253 | + setWarningMessage(`${t('Query is slow')}`); |
| 254 | + } |
| 255 | + } |
| 256 | + ); |
| 257 | + }, |
| 258 | + // i18n t dependency kills jest |
| 259 | + // eslint-disable-next-line react-hooks/exhaustive-deps |
| 260 | + [] |
| 261 | + ); |
| 262 | + |
243 | 263 | const tick = React.useCallback(() => { |
244 | 264 | setLoading(true); |
245 | 265 | setError(undefined); |
246 | 266 | const fq = buildFlowQuery(); |
247 | 267 | switch (selectedViewId) { |
248 | 268 | case 'table': |
249 | | - getFlows(fq) |
250 | | - .then(result => { |
251 | | - setFlows(result.records); |
252 | | - setStats(result.stats); |
253 | | - }) |
254 | | - .catch(err => { |
255 | | - setFlows([]); |
256 | | - setError(getHTTPErrorDetails(err)); |
257 | | - }) |
258 | | - .finally(() => { |
259 | | - setLoading(false); |
260 | | - }); |
| 269 | + manageWarnings( |
| 270 | + getFlows(fq) |
| 271 | + .then(result => { |
| 272 | + setFlows(result.records); |
| 273 | + setStats(result.stats); |
| 274 | + }) |
| 275 | + .catch(err => { |
| 276 | + setFlows([]); |
| 277 | + setError(getHTTPErrorDetails(err)); |
| 278 | + setWarningMessage(undefined); |
| 279 | + }) |
| 280 | + .finally(() => { |
| 281 | + setLoading(false); |
| 282 | + }) |
| 283 | + ); |
261 | 284 | break; |
262 | 285 | case 'topology': |
263 | | - getTopology(fq, range) |
264 | | - .then(result => { |
265 | | - setMetrics(result.metrics); |
266 | | - setStats(result.stats); |
267 | | - }) |
268 | | - .catch(err => { |
269 | | - setMetrics([]); |
270 | | - setError(getHTTPErrorDetails(err)); |
271 | | - }) |
272 | | - .finally(() => { |
273 | | - setLoading(false); |
274 | | - }); |
| 286 | + manageWarnings( |
| 287 | + getTopology(fq, range) |
| 288 | + .then(result => { |
| 289 | + setMetrics(result.metrics); |
| 290 | + setStats(result.stats); |
| 291 | + }) |
| 292 | + .catch(err => { |
| 293 | + setMetrics([]); |
| 294 | + setError(getHTTPErrorDetails(err)); |
| 295 | + setWarningMessage(undefined); |
| 296 | + }) |
| 297 | + .finally(() => { |
| 298 | + setLoading(false); |
| 299 | + }) |
| 300 | + ); |
275 | 301 | break; |
276 | 302 | default: |
277 | 303 | console.error('tick called on not implemented view Id', selectedViewId); |
278 | 304 | setLoading(false); |
279 | 305 | break; |
280 | 306 | } |
281 | | - }, [buildFlowQuery, range, selectedViewId]); |
| 307 | + }, [buildFlowQuery, manageWarnings, range, selectedViewId]); |
282 | 308 |
|
283 | 309 | usePoll(tick, interval); |
284 | 310 |
|
@@ -333,11 +359,21 @@ export const NetflowTraffic: React.FC<{ |
333 | 359 | // eslint-disable-next-line react-hooks/exhaustive-deps |
334 | 360 | }, [filters]); |
335 | 361 |
|
| 362 | + //clear warning message after 10s |
| 363 | + React.useEffect(() => { |
| 364 | + if (warningTimeOut.current) { |
| 365 | + clearTimeout(warningTimeOut.current); |
| 366 | + } |
| 367 | + |
| 368 | + warningTimeOut.current = setTimeout(() => setWarningMessage(undefined), 10000); |
| 369 | + }, [warningMessage]); |
| 370 | + |
336 | 371 | // updates table filters and clears up the table for proper visualization of the |
337 | 372 | // updating process |
338 | 373 | const updateTableFilters = (f: Filter[]) => { |
339 | 374 | setFilters(f); |
340 | 375 | setFlows([]); |
| 376 | + setWarningMessage(undefined); |
341 | 377 | }; |
342 | 378 |
|
343 | 379 | const clearFilters = () => { |
@@ -711,6 +747,18 @@ export const NetflowTraffic: React.FC<{ |
711 | 747 | range={range} |
712 | 748 | filters={forcedFilters ? forcedFilters : filters} |
713 | 749 | /> |
| 750 | + {!_.isEmpty(warningMessage) && ( |
| 751 | + <Alert |
| 752 | + id="netflow-warning" |
| 753 | + title={warningMessage} |
| 754 | + variant="warning" |
| 755 | + actionClose={<AlertActionCloseButton onClose={() => setWarningMessage(undefined)} />} |
| 756 | + > |
| 757 | + {hasIndexFields(filters) |
| 758 | + ? t('Add more filters or decrease limit / range to improve the query performance') |
| 759 | + : t('Add Namespace, Owner or Resource filters (which use indexed fields) to improve the query performance')} |
| 760 | + </Alert> |
| 761 | + )} |
714 | 762 | </PageSection> |
715 | 763 | ) : null; |
716 | 764 | }; |
|
0 commit comments