-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Add search functionality to Web UI and Connect ssh terminal #48776
Conversation
8bb4881
to
93d9d74
Compare
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
function search(value: string, prev?: boolean) { | ||
if (!xTerm) { | ||
return; | ||
} | ||
const match = theme.colors.terminal.brightYellow; | ||
const activeMatch = theme.colors.terminal.yellow; | ||
setSearchValue(value); | ||
|
||
xTerm.search(value, prev, { | ||
decorations: { | ||
matchOverviewRuler: match, | ||
activeMatchColorOverviewRuler: activeMatch, | ||
matchBackground: match, | ||
activeMatchBackground: activeMatch, | ||
}, | ||
}); | ||
} | ||
|
||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
search(e.target.value); | ||
}; | ||
|
||
const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { | ||
if (e.key === 'Enter') { | ||
search(e.currentTarget.value); | ||
} | ||
}; | ||
|
||
function searchNext() { | ||
search(searchValue); | ||
} | ||
|
||
function searchPrevious() { | ||
search(searchValue, true /* search for previous result */); | ||
} | ||
|
||
const onEscape = useCallback(() => { | ||
onClose(); | ||
xTerm.clearSearch(); | ||
xTerm.term.focus(); | ||
}, [xTerm, onClose]); | ||
|
||
const onSearchResultsChange = useCallback( | ||
(resultIndex: number, resultCount: number) => { | ||
setSearchResults({ resultIndex, resultCount }); | ||
}, | ||
[] | ||
); |
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 has a mixture of const x = () => {}
, function y() { }
and const z = useCallback(() => {}, [])
- we should be consistent. My personal preference is useCallback
.
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.
fair enough. i prefer function y()
but i use const when doing useCallback
and then a few other cheeky bare const got thrown in there. i'll switch to const and useCallback
when needed. thanks
86cd4df
to
a930d3e
Compare
rebased due to conflict. PR feedback handled here and on a930d3e |
🤖 Vercel preview here: https://docs-6wic0fycq-goteleport.vercel.app/docs/ver/preview |
🤖 Vercel preview here: https://docs-hyszxa56h-goteleport.vercel.app/docs/ver/preview |
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
const isSearchKeyboardEvent = useCallback( | ||
(e: KeyboardEvent) => { | ||
return ( | ||
e.type === 'keydown' && |
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.
We don't have this check in Web. Why is it needed?
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 just saw other spots in Connect focusing specifically on keydown, didn't think too much on it. I can remove as the method being called on true
is idempotent and shouldn't matter on keyup/keydown or duplicates
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.
As discussed in DMs, let's move this check to the TerminalSearch
level.
🤖 Vercel preview here: https://docs-hh226fzu8-goteleport.vercel.app/docs/ver/preview |
return false; | ||
} | ||
// this escape is handled if pressing escape with the term focused | ||
if (e.key === 'Escape') { |
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'm not sure if we need the "global" Escape handler, some terminals only close the search when you have the input focused.
But if you want to keep it, we should run it only if the search is shown. Otherwise, we will intercept all Escape key events, even when we don't need them.
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 see that you added a check in onKeyDown
. However, this place doesn't need to care about it at all, onKeyDown
is called only when the input is open.
But we still need to address the issue in registerCustomKeyEventHandler
. We don't want to intercept Escape events when the search is closed.
I actually think we should remove closing the search from there. If you take a look at the file transfer, Escape closes it only when it is focused. I think it makes sense to have the same behavior for the search.
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.
Ah i see. Ok, I've removed it from register
and now only check in onKeyDown
for the search input. also, I've remove dthe show
check on that because onKeyDown
can only be called when the input is showing anyway. Let me know if it's good now 👍
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
const isSearchKeyboardEvent = useCallback( | ||
(e: KeyboardEvent) => { | ||
return ( | ||
e.type === 'keydown' && |
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.
As discussed in DMs, let's move this check to the TerminalSearch
level.
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.test.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
🤖 Vercel preview here: https://docs-4jvhqgopl-goteleport.vercel.app/docs/ver/preview |
🤖 Vercel preview here: https://docs-pl6lbgnzq-goteleport.vercel.app/docs/ver/preview |
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.
Left some minor comments, we are almost there!
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
return false; | ||
} | ||
// this escape is handled if pressing escape with the term focused | ||
if (e.key === 'Escape') { |
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 see that you added a check in onKeyDown
. However, this place doesn't need to care about it at all, onKeyDown
is called only when the input is open.
But we still need to address the issue in registerCustomKeyEventHandler
. We don't want to intercept Escape events when the search is closed.
I actually think we should remove closing the search from there. If you take a look at the file transfer, Escape closes it only when it is focused. I think it makes sense to have the same behavior for the search.
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
web/packages/shared/components/TerminalSearch/TerminalSearch.tsx
Outdated
Show resolved
Hide resolved
🤖 Vercel preview here: https://docs-6xbf6tt6p-goteleport.vercel.app/docs/ver/preview |
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.
Left some lasts comments.
🚢
*/ | ||
|
||
import { render, act, screen } from 'design/utils/testing'; | ||
import 'jest-canvas-mock'; |
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 think 'jest-canvas-mock'
and import '@testing-library/jest-dom'
do nothing.
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.
they were used before but i dont think anything is needed with them now.
})), | ||
})); | ||
|
||
const createMockXTerm = () => { |
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.
Let's remove the references to xterm
in tests/stories as well, I'd just name it terminalMock
.
}, [ | ||
onEscape, | ||
onOpen, | ||
searchInputRef, | ||
terminalSearcher, | ||
show, | ||
isSearchKeyboardEvent, | ||
]); |
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.
There are some unnecessary deps:
}, [ | |
onEscape, | |
onOpen, | |
searchInputRef, | |
terminalSearcher, | |
show, | |
isSearchKeyboardEvent, | |
]); | |
}, [isSearchKeyboardEvent, onOpen, terminalSearcher]); |
@@ -27,6 +27,7 @@ import { | |||
FileTransferRequests, | |||
FileTransferContextProvider, | |||
} from 'shared/components/FileTransfer'; | |||
import { TerminalSearch } from 'shared/components/TerminalSearch/TerminalSearch'; |
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.
import { TerminalSearch } from 'shared/components/TerminalSearch/TerminalSearch'; | |
import { TerminalSearch } from 'shared/components/TerminalSearch'; |
import { | ||
FileTransferActionBar, | ||
FileTransfer, | ||
FileTransferContextProvider, | ||
} from 'shared/components/FileTransfer'; | ||
import { TerminalSearch } from 'shared/components/TerminalSearch/TerminalSearch'; |
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.
import { TerminalSearch } from 'shared/components/TerminalSearch/TerminalSearch'; | |
import { TerminalSearch } from 'shared/components/TerminalSearch'; |
@@ -254,6 +258,7 @@ const getDefaultKeymap = ( | |||
openProfiles: 'Ctrl+Shift+I', | |||
terminalCopy: 'Ctrl+Shift+C', | |||
terminalPaste: 'Ctrl+Shift+V', | |||
terminalSearch: 'Ctrl+F', |
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 just checked the terminal apps on Windows and Linux and they use Ctrl+Shift+F for search. I believe it's because Ctrl+F is used to move the cursor one character forward in bash. Please switch these shortcuts from Ctrl+F in Connect to Ctrl+Shift+F (and remember about updating the docs).
FYI we will have the same problem in Web UI where we overwrite Ctrl+F. We have no choice on Linux and Windows where this is a combination that opens the native search anyway. On macOS in theory we could only intercept Meta+F and leave Ctrl+F for the terminal, but I think we don't have a reliable way to test if the user is on Mac. So I guess we have to leave it as is.
@ryanclark im about to finish gz's last comments. anything left from you? |
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.
all good from me
39f2cde
to
71a9914
Compare
🤖 Vercel preview here: https://docs-g9ear6eqx-goteleport.vercel.app/docs |
Backport #48776 to branch/v16 changelog: You can now search text within ssh sessions in the Web UI and Teleport Connect
Backport #48776 to branch/v16 changelog: You can now search text within ssh sessions in the Web UI and Teleport Connect
This will add the
xterm/search-addon
addon to our terminals in the web UI ssh sessions as well as Connect. The design of the search UI was inspired by the native browser search in Chrome.Originally, it was thought that the search addon came with a built-in UI but apparently that isn't the case, so we had to do it ourselves.
Screen.Recording.2024-11-07.at.4.50.01.PM.mov
closes: #38957
changelog: You can now search text within ssh sessions in the Web UI and Teleport Connect