Skip to content

Commit 1c02e11

Browse files
committed
fix: Reduce useEffect dependencies to avoid cancelled requests.
Previously, excess dependencies caused unwanted triggering of the effect, which canceled the previous request, and was not properly handled. Now there are no unwanted triggers, and cancelation caused by rapid clicking of the focus or refresh button is handled properly.
1 parent 2da72ca commit 1c02e11

2 files changed

Lines changed: 45 additions & 55 deletions

File tree

web/locales/en/plugin__troubleshooting-panel-console-plugin.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
"Advanced": "Advanced",
33
"Ago": "Ago",
44
"Correlation result was empty.": "Correlation result was empty.",
5-
"Create a graph of correlated items from resources in the current view.": "Create a graph of correlated items from resources in the curret view.",
5+
"Create a graph of items correlated from resources in the current page.": "Create a graph of items correlated from resources in the current page.",
66
"Distance": "Distance",
77
"Find all paths to items of the specified goal class.": "Find all paths to items of the specified goal class.",
88
"Focus": "Focus",
99
"Follows correlation rules from the starting point to find related data, then continues the search from that data, up to the number of steps you specify.": "Follows correlation rules from the starting point to find related data, then continues the search from that data, up to the number of steps you specify.",
1010
"Goal Class": "Goal Class",
1111
"Korrel8r Error": "Korrel8r Error",
12+
"Loading": "Loading",
1213
"Logging Plugin Disabled": "Logging Plugin Disabled",
1314
"Netflow Plugin Disabled": "Netflow Plugin Disabled",
1415
"No Correlated Signals Found": "No Correlated Signals Found",
@@ -24,7 +25,7 @@
2425
"Search Type": "Search Type",
2526
"Selects the starting point for correlation search. This query is set automatically by the <1>Focus</1> button. You can edit it manually to specify a custom query.": "Selects the starting point for correlation search. This query is set automatically by the <1>Focus</1> button. You can edit it manually to specify a custom query.",
2627
"Since": "Since",
27-
"The current view does not support correlation.": "The current view does not support correlation.",
28+
"The current page does not support correlation.": "The current page does not support correlation.",
2829
"Time": "Time",
2930
"to": "to",
3031
"Troubleshooting": "Troubleshooting",

web/src/components/Korrel8rPanel.tsx

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ export default function Korrel8rPanel() {
5151
});
5252
const dispatch = useDispatch();
5353

54-
// State
5554
const alertRules = useSelector((state: State) => state.observe?.get('rules'));
5655
const alertIDs = React.useMemo(() => {
5756
if (!alertRules) return new Map<string, string>();
@@ -62,79 +61,67 @@ export default function Korrel8rPanel() {
6261
[alertIDs],
6362
);
6463
const locationQuery = useLocationQuery(domains);
64+
65+
// Search parameters.
6566
const [search, setSearch] = React.useState<Search>({
6667
...defaultSearch, // Default search parameters.
67-
queryStr: locationQuery?.toString(), // Default query string.
68+
queryStr: locationQuery?.toString(), // Default query string from location.
6869
...searchResult?.search, // Use persisted search if available.
6970
});
71+
// Search result
7072
const [result, setResult] = React.useState<Result | null>(searchResult?.result ?? null);
73+
// Showing advanced query
7174
const [showQuery, setShowQuery] = React.useState(false);
7275

73-
const focusTip = t('Create a graph of correlated items from resources in the current view.');
74-
const cannotFocus = t('The current view does not support correlation.');
75-
7676
React.useEffect(() => {
77-
// Set result = null to trigger a new client request, don't run the query till then.
78-
if (result !== null) {
79-
return;
80-
}
81-
if (!search?.queryStr && !locationQuery) {
82-
setResult({ message: cannotFocus });
83-
return;
84-
}
8577
// eslint-disable-next-line no-console
8678
console.debug('korrel8r search', search);
8779
const queryStr = search?.queryStr?.trim();
8880
const start: api.Start = {
8981
queries: queryStr ? [queryStr] : undefined,
9082
constraint: search?.constraint?.toAPI() ?? undefined,
9183
};
92-
const cancellableFetch =
84+
let cancelled = false; // Detect if returned cleanup function was called.
85+
const onResult = (newResult: Result) => {
86+
if (!cancelled) {
87+
setResult(newResult);
88+
dispatch(setPersistedSearch({ search, result: newResult }));
89+
}
90+
// eslint-disable-next-line no-console
91+
console.debug('korrel8r result', newResult, 'cancelled', cancelled);
92+
};
93+
const fetch =
9394
search.type === SearchType.Goal
9495
? getGoalsGraph({ start, goals: [search.goal] })
9596
: getNeighborsGraph({ start, depth: search.depth });
96-
97-
cancellableFetch
98-
.then((response: api.Graph) => {
99-
const result: Result = { graph: new korrel8r.Graph(response) };
100-
// eslint-disable-next-line no-console
101-
console.debug('korrel8r result', result);
102-
setResult(result);
103-
dispatch(setPersistedSearch({ search, result }));
104-
})
97+
fetch
98+
.then((response: api.Graph) => onResult({ graph: new korrel8r.Graph(response) }))
10599
.catch((e: api.ApiError) => {
106-
const result = {
107-
message: e.body?.error || e.message || 'Unknown Error',
100+
onResult({
108101
title: e?.body?.error ? t('Korrel8r Error') : t('Request Failed'),
109-
};
110-
// eslint-disable-next-line no-console
111-
console.debug('korrel8r result', result);
112-
setResult(result);
113-
dispatch(setPersistedSearch({ search, result }));
102+
message: e?.body?.error || e.message || 'Unknown Error',
103+
});
114104
});
115-
return () => cancellableFetch.cancel();
116-
}, [result, t, dispatch, search, cannotFocus, locationQuery]);
105+
return () => {
106+
cancelled = true;
107+
fetch.cancel();
108+
};
109+
}, [search, t, dispatch]);
117110

118111
const queryToggleID = 'query-toggle';
119112
const queryContentID = 'query-content';
120113
const queryInputID = 'query-input';
121114

122-
const depthBounds = applyBounds(1, 10);
123-
124-
const runSearch = React.useCallback(
125-
(newSearch: Search) => {
126-
// Update constraint from time period
127-
if (newSearch.period) {
128-
const [start, end] = newSearch.period.startEnd();
129-
newSearch.constraint = new korrel8r.Constraint({ ...newSearch.constraint, start, end });
130-
}
131-
newSearch.depth = depthBounds(newSearch.depth);
132-
newSearch.type = !newSearch.goal ? SearchType.Distance : newSearch.type;
133-
setSearch(newSearch);
134-
setResult(null);
135-
},
136-
[setResult, depthBounds],
137-
);
115+
const runSearch = React.useCallback((newSearch: Search) => {
116+
// Update constraint from time period
117+
if (newSearch.period) {
118+
const [start, end] = newSearch.period.startEnd();
119+
newSearch.constraint = new korrel8r.Constraint({ ...newSearch.constraint, start, end });
120+
}
121+
newSearch.depth = Math.max(1, Math.min(newSearch.depth, 10));
122+
setSearch({ ...newSearch }); // Create a new search object to trigger useEffect
123+
setResult(null);
124+
}, []);
138125

139126
const queryHelp = (
140127
<>
@@ -153,7 +140,13 @@ export default function Korrel8rPanel() {
153140
);
154141

155142
const focusButton = (
156-
<Tooltip content={locationQuery ? focusTip : cannotFocus}>
143+
<Tooltip
144+
content={
145+
locationQuery
146+
? t('Create a graph of items correlated from resources in the current page.')
147+
: t('The current page does not support correlation.')
148+
}
149+
>
157150
<Button
158151
isAriaDisabled={!locationQuery}
159152
onClick={() => {
@@ -346,7 +339,3 @@ const TopologyInfoState: React.FC<TopologyInfoStateProps> = ({ titleText, text,
346339
</div>
347340
);
348341
};
349-
350-
const applyBounds = (min: number, max: number) => {
351-
return (val: number) => Math.max(min, Math.min(val, max));
352-
};

0 commit comments

Comments
 (0)