-
Notifications
You must be signed in to change notification settings - Fork 8.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix unable to navigate away from 'Timeline' when additional filter is applied #111369
Fix unable to navigate away from 'Timeline' when additional filter is applied #111369
Conversation
cbdad15
to
0f8401d
Compare
Pinging @elastic/security-threat-hunting (Team:Threat Hunting) |
Pinging @elastic/security-solution (Team: SecuritySolution) |
@elasticmachine merge upstream |
f3c8b65
to
ef5124e
Compare
63a9918
to
9330818
Compare
@@ -18,6 +20,10 @@ export const RouteCapture = memo(({ children }) => { | |||
const location: AppLocation = useLocation(); | |||
const dispatch = useDispatch(); | |||
|
|||
useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is a revert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this dispatch looks like it should be somewhere inside a middleware and not on this component. This component can easily become cluttered with unrelated domain-specific logic if we were to follow this pattern.
is there a timeline id middleware where you can instead listen to the userChangedUrl and dispatch this action there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you. This changed was reintroduced because I reverted a fix that had moved it to somewhere else. Today most routing logic of security threat hunting is inside x-pack/plugins/security_solution/public/common/components/url_state/use_url_state.tsx
. I am working on refactoring this file, so I will consider moving this change back there.
@@ -438,35 +440,13 @@ describe('Navigation Breadcrumbs', () => { | |||
}, | |||
]); | |||
}); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is a revert
})) | ||
); | ||
} | ||
export const useSetBreadcrumbs = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that the redirect loop doesn't happen we can easily dispatch(timelineActions.showTimeline
to close the timeline
getUrlForApp: GetUrlForApp | ||
): ChromeBreadcrumb[] | null => { | ||
const spyState: RouteSpyState = omit('navTabs', objectParam); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is a revert
setInitialStateFromUrl, | ||
updateTimeline, | ||
updateTimelineIsLoading, | ||
urlState, | ||
}: UrlStateContainerPropTypes) => { | ||
const [isInitializing, setIsInitializing] = useState(true); | ||
const { filterManager, savedQueries } = useKibana().services.data.query; | ||
const { pathname: pathName, search } = useLocation(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the fix! 🎉🍾 🥳
pathName
and search
were passed as props from the redux store, which gets out of sync with the real pathname in the URL. So later on in the code when we used to call histoty.replace(outdatedPathname, ...)
. It was redirecting the user to the previous page creating the redirect loop.
@@ -226,10 +221,9 @@ export const useUrlStateHooks = ({ | |||
}); | |||
} else if (pathName !== prevProps.pathName) { | |||
handleInitialize(type, isDetectionsPages(pageName)); | |||
dispatch(timelineActions.showTimeline({ id: TimelineId.active, show: false })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is from a revert
962333c
to
7eff83c
Compare
05d9f99
to
8ef0235
Compare
34b259f
to
96d06af
Compare
// * Redirects as "security/hosts" -> "security/hosts/allHosts" | ||
// * It also happens once on every location change because browserPathName gets updated before pathName | ||
// *Warning*: Removing this return would cause redirect loops that crashes the APP. | ||
if (browserPathName !== pathName) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Whenever the redux store changes, useUrlStateHooks updates the URL to sync with the store content. But when we navigate to a different page, it is also called to build the new page query string. If we update the store and navigate to a URL in a small time window, it could create an endless loop of useUrlStateHooks calls because the current URL doesn't get passed down to the router props. So when calling history.replace to update the query string, it would redirect to the previous page.
… open (elastic#104288)" This reverts commit 1ae7afd.
…open (elastic#101568)" This reverts commit 5b0d325.
…s open" Since the redirect loop is fixed we can easily dispatch an action to close the timeline.
96d06af
to
f1aec7e
Compare
💚 Build Succeeded
Metrics [docs]Async chunks
History
To update your PR or re-run it, just comment with: cc @machadoum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🔥 🚢
(ps. thanks for the comment in useUrlState()
👏
@@ -175,6 +172,14 @@ export const useUrlStateHooks = ({ | |||
}; | |||
|
|||
useEffect(() => { | |||
// When browser location and store location are out of sync, skip the execution. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment - supper helpful for the "future" us 😄
… applied (elastic#111369) * Fix useUrlStateHooks endless redirect loop Whenever the redux store changes, useUrlStateHooks updates the URL to sync with the store content. But when we navigate to a different page, it is also called to build the new page query string. If we update the store and navigate to a URL in a small time window, it could create an endless loop of useUrlStateHooks calls because the current URL doesn't get passed down to the router props. So when calling history.replace to update the query string, it would redirect to the previous page. * Revert "Fix Kibana page crash on redirect navigation when timeline is open (elastic#104288)" This reverts commit 1ae7afd. * Revert "Fix breadcrumbs path reopens timeline when timeline modal is open (elastic#101568)" This reverts commit 5b0d325. * Fix properly "breadcrumbs path reopens timeline when timeline modal is open" Since the redirect loop is fixed we can easily dispatch an action to close the timeline. * Fix eslint issue
💔 Backport failed
Successful backport PRs will be merged automatically after passing CI. To backport manually run: |
… applied (#111369) (#112546) * Fix useUrlStateHooks endless redirect loop Whenever the redux store changes, useUrlStateHooks updates the URL to sync with the store content. But when we navigate to a different page, it is also called to build the new page query string. If we update the store and navigate to a URL in a small time window, it could create an endless loop of useUrlStateHooks calls because the current URL doesn't get passed down to the router props. So when calling history.replace to update the query string, it would redirect to the previous page. * Revert "Fix Kibana page crash on redirect navigation when timeline is open (#104288)" This reverts commit 1ae7afd. * Revert "Fix breadcrumbs path reopens timeline when timeline modal is open (#101568)" This reverts commit 5b0d325. * Fix properly "breadcrumbs path reopens timeline when timeline modal is open" Since the redirect loop is fixed we can easily dispatch an action to close the timeline. * Fix eslint issue Co-authored-by: Pablo Machado <pablo.nevesmachado@elastic.co>
… applied (elastic#111369) * Fix useUrlStateHooks endless redirect loop Whenever the redux store changes, useUrlStateHooks updates the URL to sync with the store content. But when we navigate to a different page, it is also called to build the new page query string. If we update the store and navigate to a URL in a small time window, it could create an endless loop of useUrlStateHooks calls because the current URL doesn't get passed down to the router props. So when calling history.replace to update the query string, it would redirect to the previous page. * Revert "Fix Kibana page crash on redirect navigation when timeline is open (elastic#104288)" This reverts commit 1ae7afd. * Revert "Fix breadcrumbs path reopens timeline when timeline modal is open (elastic#101568)" This reverts commit 5b0d325. * Fix properly "breadcrumbs path reopens timeline when timeline modal is open" Since the redirect loop is fixed we can easily dispatch an action to close the timeline. * Fix eslint issue # Conflicts: # x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.test.ts
… applied (#111369) (#112637) * Fix useUrlStateHooks endless redirect loop Whenever the redux store changes, useUrlStateHooks updates the URL to sync with the store content. But when we navigate to a different page, it is also called to build the new page query string. If we update the store and navigate to a URL in a small time window, it could create an endless loop of useUrlStateHooks calls because the current URL doesn't get passed down to the router props. So when calling history.replace to update the query string, it would redirect to the previous page. * Revert "Fix Kibana page crash on redirect navigation when timeline is open (#104288)" This reverts commit 1ae7afd. * Revert "Fix breadcrumbs path reopens timeline when timeline modal is open (#101568)" This reverts commit 5b0d325. * Fix properly "breadcrumbs path reopens timeline when timeline modal is open" Since the redirect loop is fixed we can easily dispatch an action to close the timeline. * Fix eslint issue # Conflicts: # x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.test.ts
issue: #109802
Summary
useLocation
setBreadcrumbs
to dispatch an "close timeline" action when clicked.Quick explanation
After fixing the redirect loop properly, I could revert the previous commits that tried to fix it. I also reverted a fix for closing the modal when breadcrumbs links are clicked because now we can easily dispatch close timeline action without causing a redirect loop.
Long explanation
We have recurrent issues related to closing the timeline and navigating to other pages. The current issue was introduced on the following fix attempt:
#104288
Original issue:
Whenever the redux store changes,
useUrlStateHooks
updates the URL to sync with the store content. But when we navigate to a different page, it is also called to build the new page query string. If we update the store and navigate to a URL in a small time window, it could create an endless loop ofuseUrlStateHooks
calls because the current URL doesn't get passed down to the router props. So when callinghistory.replace
to update the query string, it would redirect to the previous page.I tried to fix it before by moving
timeline.isOpen
dispatch to insideuseUrlStateHooks
, so the loop wouldn't happen. But that also creates more bugs. Like the ones described below:Bug one
Bug two
To fix this problem once and for all, I have stepped back. I reverted the two previous fixes, and I am tackling the core issue. When calling
history.replace
to update a query string in the URL, it will usewindow.location
instead of the path inside router props. This way, the redirect loop won't happen anymore.How to test it
Open the timeline and try to click on every link to any possible page. It should close the timeline and never crash 🙏
Checklist