feat: Tag search will now only show the direct tag results instead of also showing the parent and siblings (#2906)

This commit is contained in:
Aman Harwara
2025-06-24 12:32:27 +05:30
committed by GitHub
parent c050a2cd33
commit caa8eff216
5 changed files with 63 additions and 14 deletions

View File

@@ -38,8 +38,11 @@ export function itemMatchesQuery(
searchQuery: SearchQuery,
collection: ReferenceLookupCollection,
): boolean {
const shouldCheckForSomeTagMatches = searchQuery.shouldCheckForSomeTagMatches ?? true
const itemTags = collection.elementsReferencingElement(itemToMatch, ContentType.TYPES.Tag) as SNTag[]
const someTagsMatches = itemTags.some((tag) => matchResultForStringQuery(tag, searchQuery.query) !== MatchResult.None)
const someTagsMatches =
shouldCheckForSomeTagMatches &&
itemTags.some((tag) => matchResultForStringQuery(tag, searchQuery.query) !== MatchResult.None)
if (itemToMatch.protected && !searchQuery.includeProtectedNoteText) {
const match = matchResultForStringQuery(itemToMatch, searchQuery.query)

View File

@@ -5,6 +5,7 @@ import { SearchableItem } from './SearchableItem'
export type SearchQuery = {
query: string
includeProtectedNoteText: boolean
shouldCheckForSomeTagMatches?: boolean
}
export interface ReferenceLookupCollection {

View File

@@ -6,16 +6,26 @@ import { TagListSectionType } from './TagListSection'
import { TagsListItem } from './TagsListItem'
import { useApplication } from '../ApplicationProvider'
import { useListKeyboardNavigation } from '@/Hooks/useListKeyboardNavigation'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
type Props = {
type: TagListSectionType
}
function getAllTagsForType(controller: NavigationController, type: TagListSectionType) {
if (type === 'all') {
if (controller.isSearching) {
return controller.tags
}
return controller.allLocalRootTags
}
return controller.starredTags
}
const TagsList: FunctionComponent<Props> = ({ type }: Props) => {
const application = useApplication()
const allTags =
type === 'all' ? application.navigationController.allLocalRootTags : application.navigationController.starredTags
const allTags = getAllTagsForType(application.navigationController, type)
const openTagContextMenu = useCallback(
(x: number, y: number) => {

View File

@@ -26,6 +26,8 @@ import { log, LoggingDomain } from '@/Logging'
import { NoteDragDataFormat, TagDragDataFormat } from './DragNDrop'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { useApplication } from '../ApplicationProvider'
import { mergeRefs } from '../../Hooks/mergeRefs'
import { getTitleForLinkedTag } from '../../Utils/Items/Display/getTitleForLinkedTag'
type Props = {
tag: SNTag
@@ -46,6 +48,8 @@ export const TagsListItem: FunctionComponent<Props> = observer(
const [title, setTitle] = useState(tag.title || '')
const [subtagTitle, setSubtagTitle] = useState('')
const tagRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null)
const subtagInputRef = useRef<HTMLInputElement>(null)
const menuButtonRef = useRef<HTMLAnchorElement>(null)
@@ -75,6 +79,8 @@ export const TagsListItem: FunctionComponent<Props> = observer(
const [isBeingDraggedOver, setIsBeingDraggedOver] = useState(false)
const tagHierarchyPrefix = navigationController.isSearching && getTitleForLinkedTag(tag, application)?.titlePrefix
useEffect(() => {
if (!hadChildren && hasChildren) {
setShowChildren(true)
@@ -117,6 +123,18 @@ export const TagsListItem: FunctionComponent<Props> = observer(
const selectCurrentTag = useCallback(async () => {
await navigationController.setSelectedTag(tag, type, {
userTriggered: true,
scrollIntoView: false,
})
}, [navigationController, tag, type])
const clearSearchAndSelectCurrentTag = useCallback(async () => {
if (!navigationController.isSearching) {
return
}
navigationController.setSearchQuery('')
await navigationController.setSelectedTag(tag, type, {
userTriggered: true,
scrollIntoView: true,
})
}, [navigationController, tag, type])
@@ -196,8 +214,6 @@ export const TagsListItem: FunctionComponent<Props> = observer(
[navigationController, onContextMenu, tag, type],
)
const tagRef = useRef<HTMLDivElement>(null)
const { addDragTarget, removeDragTarget } = useFileDragNDrop()
useEffect(() => {
@@ -292,6 +308,7 @@ export const TagsListItem: FunctionComponent<Props> = observer(
isBeingDraggedOver && 'is-drag-over',
)}
onClick={selectCurrentTag}
onDoubleClick={clearSearchAndSelectCurrentTag}
onKeyDown={(event) => {
if (event.key === KeyboardKey.Enter || event.key === KeyboardKey.Space) {
selectCurrentTag().catch(console.error)
@@ -301,7 +318,18 @@ export const TagsListItem: FunctionComponent<Props> = observer(
setTagExpanded(true)
}
}}
ref={tagRef}
ref={mergeRefs([
tagRef,
function scrollIntoViewIfNeeded(el) {
if (!el || navigationController.tagToScrollIntoView !== tag) {
return
}
el.scrollIntoView({
block: 'center',
})
navigationController.tagToScrollIntoView = undefined
},
])}
style={{
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
}}
@@ -330,9 +358,7 @@ export const TagsListItem: FunctionComponent<Props> = observer(
{isEditing && (
<input
className={
'title editing overflow-hidden text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item'
}
className="title editing min-w-0 overflow-hidden text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item"
id={`react-tag-${tag.uuid}-${type}`}
onBlur={onBlur}
onInput={onInput}
@@ -346,11 +372,10 @@ export const TagsListItem: FunctionComponent<Props> = observer(
{!isEditing && (
<>
<div
className={
'title overflow-hidden text-left text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item'
}
className="title overflow-hidden text-left text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item"
id={`react-tag-${tag.uuid}-${type}`}
>
{tagHierarchyPrefix && <span className="opacity-50">{tagHierarchyPrefix}</span>}
{title}
</div>
</>

View File

@@ -59,6 +59,7 @@ export class NavigationController
previouslySelected_: AnyTag | undefined = undefined
editing_: SNTag | SmartView | undefined = undefined
addingSubtagTo: SNTag | undefined = undefined
tagToScrollIntoView: AnyTag | undefined = undefined
contextMenuOpen = false
contextMenuClickLocation: { x: number; y: number } = { x: 0, y: 0 }
@@ -390,10 +391,14 @@ export class NavigationController
return []
}
if (this.isSearching) {
return []
}
const children = this.items.getTagChildren(tag)
const childrenUuids = children.map((childTag) => childTag.uuid)
const childrenTags = this.isSearching ? children : this.tags.filter((tag) => childrenUuids.includes(tag.uuid))
const childrenTags = this.tags.filter((tag) => childrenUuids.includes(tag.uuid))
return childrenTags
}
@@ -479,8 +484,9 @@ export class NavigationController
public async setSelectedTag(
tag: AnyTag | undefined,
location: TagListSectionType,
{ userTriggered } = { userTriggered: false },
options?: { userTriggered: boolean; scrollIntoView?: boolean },
) {
const { userTriggered = false, scrollIntoView = false } = options || {}
if (tag && tag.conflictOf) {
this._changeAndSaveItem
.execute(tag, (mutator) => {
@@ -512,6 +518,9 @@ export class NavigationController
},
InternalEventPublishStrategy.SEQUENCE,
)
if (userTriggered && scrollIntoView) {
this.tagToScrollIntoView = tag
}
})
}
@@ -678,6 +687,7 @@ export class NavigationController
searchQuery: {
query: this.searchQuery,
includeProtectedNoteText: false,
shouldCheckForSomeTagMatches: false,
},
})
this.reloadTags()