From 2b56224bc87fdb2707ecdf6567731762c15261c3 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 14 Nov 2022 17:04:12 -0500 Subject: [PATCH] adds history navigation to graph search --- CHANGELOG.md | 2 + src/webviews/apps/plus/graph/GraphWrapper.tsx | 10 +++++ .../shared/components/search/search-box.ts | 5 +++ .../shared/components/search/search-input.ts | 39 ++++++++++++++++--- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9deeaa87ddadb..b094e3e2069ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Adds a Terminal Links section to the GitLens Interactive Settings - Adds ability to reset to any commit in the _Commit Graph_ and GitLens views — closes [#2326](https://github.com/gitkraken/vscode-gitlens/issues/2326) +- Adds history navigation to the search box in the _Commit Graph_ + - when focused in the search field, using `up arrow` and `down arrow` navigates through previous searches that yielded results ### Changed diff --git a/src/webviews/apps/plus/graph/GraphWrapper.tsx b/src/webviews/apps/plus/graph/GraphWrapper.tsx index 6906d247a8109..f98ccfc35c6d5 100644 --- a/src/webviews/apps/plus/graph/GraphWrapper.tsx +++ b/src/webviews/apps/plus/graph/GraphWrapper.tsx @@ -172,6 +172,7 @@ export function GraphWrapper({ // repo selection UI const [repoExpanded, setRepoExpanded] = useState(false); // search state + const searchEl = useRef(null); const [searchQuery, setSearchQuery] = useState(undefined); const { results, resultsError } = getSearchResultModel(state); const [searchResults, setSearchResults] = useState(results); @@ -278,6 +279,14 @@ export function GraphWrapper({ useEffect(() => subscriber?.(updateState), []); + useEffect(() => { + if (searchResultsError != null || searchResults == null || searchResults.count === 0 || searchQuery == null) { + return; + } + + searchEl.current?.logSearch(searchQuery); + }, [searchResults]); + const searchPosition: number = useMemo(() => { if (searchResults?.ids == null || !searchQuery?.query) return 0; @@ -675,6 +684,7 @@ export function GraphWrapper({
2)} diff --git a/src/webviews/apps/shared/components/search/search-box.ts b/src/webviews/apps/shared/components/search/search-box.ts index 32d6dd802ba83..af17be6d21739 100644 --- a/src/webviews/apps/shared/components/search/search-box.ts +++ b/src/webviews/apps/shared/components/search/search-box.ts @@ -1,5 +1,6 @@ import { attr, css, customElement, FASTElement, html, observable, ref, volatile, when } from '@microsoft/fast-element'; import { isMac } from '@env/platform'; +import type { SearchQuery } from '../../../../../git/search'; import { pluralize } from '../../../../../system/string'; import type { Disposable } from '../../dom'; import { DOM } from '../../dom'; @@ -259,6 +260,10 @@ export class SearchBox extends FASTElement { this.$emit('navigate', details); } + logSearch(query: SearchQuery) { + this.searchInput?.logSearch(query); + } + handleShortcutKeys(e: KeyboardEvent) { if (e.altKey) return; diff --git a/src/webviews/apps/shared/components/search/search-input.ts b/src/webviews/apps/shared/components/search/search-input.ts index 3038ba31c497f..13f93bedac8d0 100644 --- a/src/webviews/apps/shared/components/search/search-input.ts +++ b/src/webviews/apps/shared/components/search/search-input.ts @@ -480,14 +480,29 @@ export class SearchInput extends FASTElement { } handleShortcutKeys(e: KeyboardEvent) { - if (e.key !== 'Enter' || e.ctrlKey || e.metaKey || e.altKey) return true; + if (!['Enter', 'ArrowUp', 'ArrowDown'].includes(e.key) || e.ctrlKey || e.metaKey || e.altKey) return true; e.preventDefault(); - if (e.shiftKey) { - this.$emit('previous'); - } else { - this.$emit('next'); + if (e.key === 'Enter') { + if (e.shiftKey) { + this.$emit('previous'); + } else { + this.$emit('next'); + } + } else if (this.searchHistory.length !== 0) { + const direction = e.key === 'ArrowDown' ? 1 : -1; + const nextPos = this.searchHistoryPos + direction; + if (nextPos > -1 && nextPos < this.searchHistory.length) { + this.searchHistoryPos = nextPos; + const value = this.searchHistory[nextPos]; + if (value !== this.value) { + this.value = value; + this.debouncedUpdateHelpText(); + this.debouncedEmitSearch(); + } + } } + return false; } @@ -522,6 +537,20 @@ export class SearchInput extends FASTElement { setCustomValidity(errorMessage: string = '') { this.errorMessage = errorMessage; } + + searchHistory: string[] = []; + searchHistoryPos = 0; + logSearch(query: SearchQuery) { + const lastIndex = this.searchHistory.length - 1; + + // prevent duplicate entries + if (this.searchHistoryPos < lastIndex || this.searchHistory[lastIndex] === query.query) { + return; + } + + this.searchHistory.push(query.query); + this.searchHistoryPos = this.searchHistory.length - 1; + } } function getSubstringFromCursor(value: string, start: number | null, end: number | null): string | undefined {