Skip to content

Retry search in Connect if current workspace cert has expired#24880

Merged
ravicious merged 10 commits intomasterfrom
ravicious/search-bar-retry
Apr 26, 2023
Merged

Retry search in Connect if current workspace cert has expired#24880
ravicious merged 10 commits intomasterfrom
ravicious/search-bar-retry

Conversation

@ravicious
Copy link
Copy Markdown
Member

@ravicious ravicious commented Apr 20, 2023

The main goal of this PR is to detect if any search request made to clusters from the current workspace has failed, if so offer the user a way to relogin and then retry the search.

We do this only for current workspace requests because otherwise we'd have to get the user through a modal for every cluster they're logged in to.

As usual, the first couple of commits are small refactors of related functions. The actual feature is implemented in the last two commits.

The best way to test it is to copy the tsh folder with the expired certs:

cp -R ~/Library/Application\ Support/Electron/tsh{,-with-expired-certs}

Then start Connect, log in to the cluster and then replace the fresh certs with expired ones:

rm -rf ~/Library/Application\ Support/Electron/tsh && cp -R ~/Library/Application\ Support/Electron/tsh{-with-expired-certs,}

The next request to the cluster should make Connect think that the certs have expired.

lockOpen -> pauseUserInteraction

The big thing is how lockOpen has been refactored into pauseUserInteraction. lockOpen was added in #24520. #24520 makes it so that when any of the requests fails, we offer the ability to open a modal which shows error details. We don't want the search bar to get closed when the user interacts with the modal, so we introduced lockOpen.

This PR shows another modal, the login modal, while the search bar is supposed to stay open. However, the login modal is much more complex than the one with error details. It not only contains some buttons, but also some form fields.

Because ResultList adds a global window listener which captures some keyboard presses, it was impossible to press Enter in the login modal while the search bar was open.

So I completely changed how lockOpen works. Instead of merely causing the close function to be a noop, I added a new function to SearchContext called addWindowEventListener. Any window listener related to the search bar should be registered through this function. addWindowEventListener is supposed to be used in useEffect and it automatically removes the listeners for the duration of pauseUserInteraction, which is the new name for lockOpen.

pauseUserInteraction is intended for those cases where we want to keep the search bar displayed while the user interacts with some other element of the UI.

Why do we need global window listeners in the first place?

One is used to detect outside clicks while the search bar is open to close the search bar. I'm not sure if there's a way to get rid of this one. The other listener is to provide keyboard navigation while the search bar is open. Grzegorz had some ideas on how to get rid of this one but the current situation is a consequence of how the components and the underlying DOM tree are structured. The input tag is rendered outside of ResultList but ResultList would need to add event listeners on the input.

lockOpen worked great when we were concerned only about user interaction
with a modal closing the search bar as well. However, in the next commit
I'm going to add a login modal that's shown if the search fails with a
retryable error.

In that scenario, pressing Enter in the modal wouldn't work, as it would
be captured by the window listener that ResultList adds.

To work around this problem, I refactored lockOpen into pauseUserInteraction.
It still works pretty much the same way. But then instead of having checking
isLockedOpen in the close function, we have a new addWindowEventListener
function.

addWindowEventListener automatically removes the listener after
pauseUserInteraction is called. This solves both the problem of closing
the modal and the problem of using the enter key in the modal.
@github-actions github-actions Bot requested review from rudream and ryanclark April 20, 2023 10:17
@ravicious ravicious requested review from avatus and gzdunek and removed request for rudream and ryanclark April 20, 2023 10:17
Copy link
Copy Markdown
Contributor

@gzdunek gzdunek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the solution with addWindowListener, looks so clean and solid!

Comment thread web/packages/teleterm/src/ui/Search/SearchContext.tsx Outdated
} = props;
const activeItemRef = useRef<HTMLDivElement>();
const [activeItemIndex, setActiveItemIndex] = useState(0);
const { addWindowEventListener } = useSearchContext();
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding useSearchContext to ResultList broke the ActionPicker story because the story was not wrapping that component in the context. I refactored ResultList to take addWindowEventListener as a prop instead. It is a pretty much a self-contained component with only presentational logic so in the end I figured it might not make sense to contaminate it with a context.

@ravicious ravicious requested a review from gzdunek April 21, 2023 10:23
@ravicious ravicious enabled auto-merge April 26, 2023 08:30
@ravicious ravicious added this pull request to the merge queue Apr 26, 2023
Merged via the queue into master with commit e32a3e5 Apr 26, 2023
@ravicious ravicious deleted the ravicious/search-bar-retry branch April 26, 2023 08:47
@public-teleport-github-review-bot
Copy link
Copy Markdown

@ravicious See the table below for backport results.

Branch Result
branch/v13 Create PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants