Skip to content

Conversation

@contributor
Copy link
Contributor

@contributor contributor commented Nov 22, 2025

If #autoExecuteSearch label is present, it auto executes a search note.

If ribbon's tab Collection Properties is present (and search results are not empty), it will auto switch to the tab too.

Context: #7704 (comment)

@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Nov 22, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @contributor, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant enhancement to how search notes function, enabling them to automatically execute their queries under specific conditions. The feature is activated by a dedicated label and includes intelligent handling to prevent repetitive executions within a session. Additionally, it integrates with the UI to automatically switch to a relevant tab, aiming to improve user efficiency and interaction with search results.

Highlights

  • Auto-execution of Search Notes: Search notes tagged with the #autoExecuteSearch label will now automatically execute their defined queries upon being opened, streamlining the user workflow.
  • Session-based Prevention of Re-execution: A new mechanism utilizing sessionStorage has been implemented to prevent the same search note from being auto-executed multiple times within a single browser session, ensuring efficiency and avoiding redundant operations.
  • Automatic Ribbon Tab Switching: When an auto-executing search note is opened in the 'default' view mode, the 'Collection Properties' ribbon tab will automatically be toggled, providing immediate access to relevant note properties.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a feature to automatically execute a search note if it has the #autoExecuteSearch label. The implementation uses sessionStorage to prevent re-executing the search for the same note within a session. The changes are mostly in SearchDefinitionTab.tsx. My review includes feedback on potential bugs related to a toggle command and missing dependencies in a useEffect hook, as well as a suggestion to improve code structure and performance.

await refreshResults();

if (noteContext?.viewScope?.viewMode === "default") {
parentComponent?.triggerCommand("toggleRibbonTabBookProperties", {});
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Using toggleRibbonTabBookProperties might lead to unexpected behavior. If the 'Collection Properties' tab is already active, this command will likely hide it, which seems contrary to the goal of ensuring it is visible. It would be safer to use a command that explicitly shows the tab, for example one with a name like showRibbonTabBookProperties, if one exists. If not, you might need to check if the tab is already active before triggering the toggle command to avoid accidentally hiding it.

}
}
autoExecute();
}, [note]);
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This useEffect has missing dependencies. According to the rules of hooks, all values from the component scope that are used inside an effect should be listed in its dependency array. In this case, noteContext and refreshResults are used inside the effect but are missing from the dependency array. This can lead to stale closures and bugs. Please add them to the array. Note that refreshResults is redefined on every render, so adding it will cause this effect to run more often. The logic inside seems to handle this, but for better performance, refreshResults should be wrapped in useCallback in a separate change.

Suggested change
}, [note]);
}, [note, noteContext, refreshResults]);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gemini-code-assist only note being changed should be a trigger to execute search. No need to trigger it more often than that.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand you want the useEffect to trigger only when note changes. However, useEffect captures the values of variables from the render it was created in. If noteContext or refreshResults change between renders where note does not change, the autoExecute function inside your useEffect will still use the old (stale) versions of noteContext and refreshResults from the last time note changed. This can lead to subtle and hard-to-debug bugs.

React's "rules of hooks" require all values used inside an effect (that come from the component scope) to be listed in the dependency array to ensure the effect always operates with the latest values.

If you truly want the effect to only re-run when note changes, you need to ensure that noteContext and refreshResults themselves have stable references across renders:

  • For refreshResults, you should wrap it in useCallback to memoize the function. This will prevent it from being recreated on every render, thus keeping its reference stable.
  • For noteContext, if it's a prop, its stability depends on the parent component. If the parent is recreating it on every render, you might need to memoize it in the parent using useMemo or ensure its structure doesn't change unnecessarily.

Until refreshResults and noteContext are guaranteed to be stable, the safest and most correct approach is to include them in the dependency array. Then, if you observe excessive re-renders, optimize refreshResults with useCallback and investigate noteContext's stability.

Comment on lines 77 to 82
const AUTO_EXEC_KEY = "lastAutoExecutedSearchNote";
return {
load: () => sessionStorage.getItem(AUTO_EXEC_KEY),
save: (noteId: string) => sessionStorage.setItem(AUTO_EXEC_KEY, noteId),
};
}, []);
Copy link
Contributor

Choose a reason for hiding this comment

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

Trilium doesn't use session storage and I'm not sure why it would need to be used here.
You have useNoteLabel which reads the label value for you automatically.
You can use useState or useRef to store the last executed note, not session storage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eliandoran this was my path: useRef -> useState -> sessionStorage. The first two didn't work, there are commits for that. The react component is recreated every time and useRef.current is reset.

In order to keep react component I would have to use stayInDom in ribbon definition. This approach is worse than sessionStorage.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why would it be worse?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would fire useEffect when you navigate away to other notes (not of search type). There is an earlier return for that in useEffect, but still this is not good approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I replaced sessionStorage with module level var, this approach better then both.

@eliandoran eliandoran marked this pull request as draft November 22, 2025 19:52
@contributor contributor marked this pull request as ready for review November 22, 2025 22:00
Copy link
Contributor

@eliandoran eliandoran left a comment

Choose a reason for hiding this comment

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

It's fine to have an attribute to execute the auto-search but I think doing it from the SearchDefinitionTab is not the best place to do so since it's a ribbon tab (e.g. user configuration).

Have you noticed that if you press the Search button in the launch bar, the search is immediately executed?

I tracked down this behavior, you can find it in root_command_executor.ts and looking for searchNotesCommand. Notice how it forces the search via loadSearchNote.

We can do the same, but you'd have to find a good place to do so. Perhaps in search_result.tsx where the logic of search not executed yet is also determine.

P.S. Don't forget to update the documentation; new features cannot be undocumented.

@eliandoran eliandoran marked this pull request as draft November 23, 2025 20:26
@contributor
Copy link
Contributor Author

@eliandoran

It's fine to have an attribute to execute the auto-search but I think doing it from the SearchDefinitionTab is not the best place to do so since it's a ribbon tab (e.g. user configuration).

autoExecute does ultimately call loadSearchNote

image

It does this by using call to existing refreshResults in the same file (SearchDefinitionTab.tsx). So it works not much differently from “manual” search.

I could extract autoExecute function to some file, but then refreshResults should be extracted too. What are advantages of that?

@contributor
Copy link
Contributor Author

@eliandoran

By the way, there is a “double list” bug in display search results. I first attributed this to the auto-search. But no, this is unrelated, and exists in main.

  • start/reload app on a text note
  • go to saved search note
  • press search button (you can do this few times with different limits)

Search results are duplicated. When there are many results, you have double scrollbars too (moving in opposite directions)

Reproducable both in current main HEAD 71b86b3, and in main's commit 435b856 this PR starts from

Screenshots

image image

@eliandoran
Copy link
Contributor

eliandoran commented Nov 24, 2025

@contributor , can you merge with the latest main to see if the issue is still reproducible? On my side I don't get double results.

Edit: I see you mentioned it occurs in the latest main as well, weird.

@contributor
Copy link
Contributor Author

@eliandoran

On my side I don't get double results.

Set these attributes on root note:
#viewType(inheritable)=list #windowName=ShouldNeverHappen #iconClass="bx bx-home-alt-2"

@eliandoran
Copy link
Contributor

eliandoran commented Nov 24, 2025

@contributor , apparently #viewType(inheritable)=list is the key.

Should be fixed in d7ae2e4.

@contributor
Copy link
Contributor Author

@contributor , apparently #viewType(inheritable)=list is the key.

Should be fixed in d7ae2e4.

@eliandoran

Still doubled result. Both in search tab and collection tab

@contributor
Copy link
Contributor Author

contributor commented Nov 25, 2025

@eliandoran

Additionally, there is another, more severe bug (including current main 3afe6df). Collection and text notes stops to show their children notes (root has #viewType(inheritable)=list)

  • open trilium on a text note from collection
  • click on collection note - it is empty
  • after that clicking on any collection or text note won't show their children
Details

Collection with children:
image

Text note with children:
image

@eliandoran
Copy link
Contributor

eliandoran commented Nov 25, 2025

@contributor , apparently #viewType(inheritable)=list is the key.
Should be fixed in d7ae2e4.

@eliandoran

Still doubled result. Both in search tab and collection tab

Can't reproduce this issue anymore, are you sure it's not a problem with the cache on your side?

Additionally, there is another, more severe bug (including current main 3afe6df). Collection and text notes stops to show their children notes (root has #viewType(inheritable)=list)

Nice catch. I was aware of the bug but did not have specific steps to reproduce it.
Should be fixed by 976b1e1.

@contributor
Copy link
Contributor Author

@eliandoran

Can't reproduce this issue anymore, are you sure it's not a problem with the cache on your side?

I'm sure. Double collection bug is still there.

Empty collection bug is now fixed.

@eliandoran
Copy link
Contributor

@contributor , what commit are you on?

@contributor
Copy link
Contributor Author

@contributor , what commit are you on?

976b1e1

@eliandoran
Copy link
Contributor

@contributor , can't reproduce it...

Recording.2025-11-25.202224.mp4

@contributor
Copy link
Contributor Author

@eliandoran

I retested again. Up until commit 976b1e1 double list is present. The commit fixes empty list. And apparently, this also fixes double list.

@rom1dep
Copy link
Contributor

rom1dep commented Nov 25, 2025

If #autoExecuteSearch label is present, it auto executes a search note.

what does that mean, practically?

@contributor
Copy link
Contributor Author

If #autoExecuteSearch label is present, it auto executes a search note.

what does that mean, practically?

If you have a saved search note, #autoExecuteSearch will executes search automatically when you click on a tree node.

I had an old abandoned "Saved searches" branch with various search notes. I added #autoExecuteSearch(inheritable) to it, and the search notes now are easy and fun to click on. I moved the most useful search notes to other parts of tree/projects (and added #autoExecuteSearch to them directly).

@contributor
Copy link
Contributor Author

@eliandoran added docs. ready for review.

@contributor contributor marked this pull request as ready for review November 26, 2025 08:27
@contributor contributor changed the title Auto execute search note Auto execute saved search note Nov 26, 2025
@rom1dep
Copy link
Contributor

rom1dep commented Nov 26, 2025

If you have a saved search note, #autoExecuteSearch will executes search automatically when you click on a tree node.

Specifically, which tree node relative to the search note needs to be interacted with for the search to be triggered?

As far as I can tell, "click to search" is a capability that already exists (via the refresh button, on the search note itself):

image

It'd be good that:

  • we don't introduce conflicting ways to do the same thing (click to refresh)
  • the new way of implementing "click to refresh" is well documented and at least as discoverable as the current one (assuming a new way is warranted).

Now, if the intent is to have "smart" search-note hierarchies that are kept up to date and rendered at all time (without needing explicit refresh, which is what #autoExecuteSearch kind of hints at), I suppose it's a much bigger effort.

@contributor
Copy link
Contributor Author

contributor commented Nov 26, 2025

Specifically, which tree node relative to the search note needs to be interacted with for the search to be triggered?

Search note itself

Now, if the intent is to have "smart" search-note hierarchies that are kept up to date and rendered at all time (without needing explicit refresh, which is what #autoExecuteSearch kind of hints at), I suppose it's a much bigger effort

Yes, this is what it does. Browsing saved searches as collections with one click on a tree node.

#autoExecuteSearch can be on a search note directly, or inherited from any note up in hierarchy

@rom1dep
Copy link
Contributor

rom1dep commented Nov 26, 2025

Specifically, which tree node relative to the search note needs to be interacted with for the search to be triggered?

Search note itself

If the search note has to be clicked on, are you sure that we need this change? By your account, this is effectively the same as clicking on the refresh button which we already have (see screenshot above), on that same note. If the need is satisfied by a larger refresh icon, let's explore a UI solution that won't pull new attributes, configuration and complexity.

Now, if the intent is to have "smart" search-note hierarchies that are kept up to date and rendered at all time (without needing explicit refresh, which is what #autoExecuteSearch kind of hints at), I suppose it's a much bigger effort

Yes, this is what it does.

Then this contradicts what you just wrote. Which one is it?

  • Are the search results guaranteed to always be up to date (reacting to notes being added/modified/deleted in the background)? If such a thing is even possible, I would be keen on making it the default, but I don't believe that this PR does this.
  • Are the search result fetched on-demand from explicit user-interaction?

Browsing saved searches as collections with one click on a tree node.

Then let's make sure that, when the collection is pegged to a search note:

  • its results are fetched/refreshed automatically when the collection is first rendered (I'm surprised because this seems to be the current behaviour here?)
  • that there is an easily accessible mean for the user to refresh the collection would the need arise
    • We already have on button in the note-tree, on the collection=search-note itself (see screenshot above)
    • We also already have the "Search" button, under "Search Parameters"
    • … do we really need more than that?

@contributor
Copy link
Contributor Author

The attribute makes new functionality opt-in.

With #autoExecuteSearch:

  • one click on a tree node to view result collection, second click to view next node and so on

Without it:

  • three clicks (while drawing a triangle with mouse cursor) to view result collection, then three clicks and triangle to view the next and so on

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

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants