Skip to content
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

Merged
merged 5 commits into from
Sep 20, 2021

Conversation

machadoum
Copy link
Member

@machadoum machadoum commented Sep 7, 2021

issue: #109802

Summary

  • Fix the redirect bug by using useLocation
  • Revert "Fix Kibana page crash on redirect navigation when timeline modal is open
  • Revert "Fix breadcrumbs path reopens timeline when timeline modal is open
  • update 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 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.

I tried to fix it before by moving timeline.isOpen dispatch to inside useUrlStateHooks , so the loop wouldn't happen. But that also creates more bugs. Like the ones described below:

Bug one

Sep-08-2021 11-37-06_low

Bug two

Sep-08-2021 11-37-40_low

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 use window.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

@machadoum machadoum self-assigned this Sep 7, 2021
@machadoum machadoum added v7.15.1 v7.16.0 v8.0.0 release_note:skip Skip the PR/issue when compiling release notes Team:Threat Hunting Security Solution Threat Hunting Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. auto-backport Deprecated - use backport:version if exact versions are needed labels Sep 7, 2021
@machadoum machadoum marked this pull request as ready for review September 8, 2021 10:51
@machadoum machadoum requested a review from a team as a code owner September 8, 2021 10:51
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-threat-hunting (Team:Threat Hunting)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

@machadoum
Copy link
Member Author

@elasticmachine merge upstream

@machadoum machadoum marked this pull request as draft September 10, 2021 13:50
@machadoum machadoum marked this pull request as ready for review September 13, 2021 14:11
@machadoum machadoum requested a review from a team as a code owner September 13, 2021 14:11
@pzl pzl requested review from paul-tavares and removed request for pzl September 13, 2021 14:20
@machadoum machadoum force-pushed the siem-timeline-issue-109802 branch 3 times, most recently from 63a9918 to 9330818 Compare September 15, 2021 09:00
@@ -18,6 +20,10 @@ export const RouteCapture = memo(({ children }) => {
const location: AppLocation = useLocation();
const dispatch = useDispatch();

useEffect(() => {
Copy link
Member Author

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

Copy link
Contributor

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?

Copy link
Member Author

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', () => {
},
]);
});

Copy link
Member Author

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 = () => {
Copy link
Member Author

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);
Copy link
Member Author

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();
Copy link
Member Author

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 }));
Copy link
Member Author

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

@machadoum machadoum force-pushed the siem-timeline-issue-109802 branch 2 times, most recently from 962333c to 7eff83c Compare September 15, 2021 11:33
@machadoum machadoum marked this pull request as draft September 15, 2021 12:11
@machadoum machadoum force-pushed the siem-timeline-issue-109802 branch 2 times, most recently from 05d9f99 to 8ef0235 Compare September 16, 2021 11:44
@machadoum machadoum marked this pull request as ready for review September 16, 2021 11:44
@machadoum machadoum force-pushed the siem-timeline-issue-109802 branch 2 times, most recently from 34b259f to 96d06af Compare September 16, 2021 13:24
// * 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;
Copy link
Contributor

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.
…s open"

Since the redirect loop is fixed we can easily dispatch an action to close the timeline.
@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 4.2MB 4.2MB +179.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @machadoum

Copy link
Contributor

@paul-tavares paul-tavares left a 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.
Copy link
Contributor

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 😄

@machadoum machadoum merged commit 8942c8b into elastic:master Sep 20, 2021
kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Sep 20, 2021
… 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
@kibanamachine
Copy link
Contributor

💔 Backport failed

Status Branch Result
7.x
7.15 Commit could not be cherrypicked due to conflicts

Successful backport PRs will be merged automatically after passing CI.

To backport manually run:
node scripts/backport --pr 111369

kibanamachine added a commit that referenced this pull request Sep 20, 2021
… 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>
machadoum added a commit to machadoum/kibana that referenced this pull request Sep 21, 2021
… 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
machadoum added a commit that referenced this pull request Sep 21, 2021
… 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed release_note:skip Skip the PR/issue when compiling release notes Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. Team:Threat Hunting Security Solution Threat Hunting Team v7.15.1 v7.16.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants