-
-
Notifications
You must be signed in to change notification settings - Fork 533
Last opened history mode show result icon instead #4057
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
base: dev
Are you sure you want to change the base?
Conversation
|
@Jack251970 @01Dri thoughts on showing the last opened with the actual result icon? Should it just show the icon instead of badge icon as well? |
|
Also, there is a bug in the comparison logic when saving history results because as seen in the screenshot 'Save Settings' result shouldn't be duplicated. |
It’s not really a bug. The equality comparison also uses the query, so in scenarios where I type “Ter” and open Terminal, and then type “Term” and open Terminal again, I end up with two history items “Ter” and “Term” both referring to the same application (Terminal), which causes duplicate results. In Query style, that makes sense because the two queries are different. CompositeKey (This name is just an example; it could be something else) |
I think the icon with the badge is more intuitive for the user, as it indicates that the item is a history entry. |
As 01Dri said, it is not a bug. Duplicated items will occur if you click A for many times. |
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.
Showing icons enhance users' experience and I agree with this change. But there is still something we need to resolve
What about just use the actual results icons, no badge?
I think we should apply filtering of duplicates when last opened style is selected. What do you think? |
@jjw24 I think we can do the filtering here as long as we keep the history in the order of execute time so that we can utilize the history list more effectively. |
|
@Jack251970 @jjw24 Sorry for the question, I’m new to the open source community. My question is: am I allowed to make the requested changes, or is this PR only for jjw? Thanks! |
You can create PR to last_history_show_result_icon branch |
Ok thanks! |
|
@01Dri just to add, of course you can, just let the PR author know what/which area you are changing to avoid overlapping. If very minor like comments, typos or small corrections to the logic that you are sure won't overlap with what the author is doing then go ahead, otherwise its good to let the PR author know you intend to help out with certain areas of the PR. Having said that, I am still making changes to this draft but help is very welcomed still. |
Added CheckIcoPathValidity to QueryHistory to set default icons for history items missing IcoPath, addressing legacy data issues. Integrated this check into MainViewModel's RefreshLastOpenedHistoryResults to guarantee icon validity before updating absolute paths.
| if (existingHistoryItem.IcoPath != result.IcoPath) | ||
| { | ||
| existingHistoryItem.IcoPath = result.IcoPath; | ||
| } |
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.
Do you think we should also copy Glyph here?
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.
Yes, I forgot about Glyph. If Glyph is different then reassign it.
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.
Yes, I forgot about Glyph. If Glyph is different then reassign it.
However, the Glyph is a init-only property. How can we edit it?
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.
Actionable comments posted: 0
♻️ Duplicate comments (1)
Flow.Launcher/ViewModel/MainViewModel.cs (1)
2-2: Remove unusedusing System.Collections;directive.The code uses only generic collections from
System.Collections.Generic. This non-generic namespace import is unused.
🧹 Nitpick comments (1)
Flow.Launcher/Storage/QueryHistory.cs (1)
73-86: Consider moving updated items to the end of the list.When an existing history item is found and updated, it remains at its original position in the list. Since
GetHistoryItemsinMainViewModel.csnow explicitly orders byExecutedDateTimedescending (line 1332), this works correctly for display. However, relying on the runtime sort rather than maintaining insertion order could lead to confusion when inspecting the raw JSON storage.If the team prefers the storage to reflect chronological order, consider removing and re-adding the item:
🔎 Optional refactor
if (LastOpenedHistoryItems.Count > 0 && TryGetLastOpenedHistoryResult(result, out var existingHistoryItem)) { + LastOpenedHistoryItems.Remove(existingHistoryItem); existingHistoryItem.ExecutedDateTime = DateTime.Now; if (existingHistoryItem.IcoPath != result.IcoPath) { existingHistoryItem.IcoPath = result.IcoPath; } + LastOpenedHistoryItems.Add(existingHistoryItem); }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Flow.Launcher/Storage/QueryHistory.csFlow.Launcher/ViewModel/MainViewModel.cs
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Learnt from: NoPlagiarism
Repo: Flow-Launcher/Flow.Launcher PR: 3104
File: Flow.Launcher.Plugin/Result.cs:73-74
Timestamp: 2024-12-02T07:37:46.838Z
Learning: In 'Result.cs', the user prefers not to add additional data URI validation in the 'IcoPath' property setter.
📚 Learning: 2026-01-05T10:06:36.650Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Applied to files:
Flow.Launcher/ViewModel/MainViewModel.csFlow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-05-01T05:38:25.673Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3500
File: Flow.Launcher/Storage/TopMostRecord.cs:145-149
Timestamp: 2025-05-01T05:38:25.673Z
Learning: For the MultipleTopMostRecord implementation in Flow.Launcher, sequence order of records in the ConcurrentBag does not need to be preserved, as confirmed by the developer. The unordered nature of ConcurrentBag is acceptable for this implementation.
Applied to files:
Flow.Launcher/ViewModel/MainViewModel.cs
📚 Learning: 2024-11-03T07:40:11.014Z
Learnt from: Yusyuriv
Repo: Flow-Launcher/Flow.Launcher PR: 3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-10-16T10:48:30.573Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3854
File: Flow.Launcher/App.xaml.cs:252-275
Timestamp: 2025-10-16T10:48:30.573Z
Learning: In Flow Launcher's App.xaml.cs, the plugin initialization block (lines 252-275) that includes PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, _mainVM.QueryResults(), and API.SaveAppAllSettings() does not require additional Task.Run wrappers or Dispatcher.InvokeAsync calls according to maintainer Jack251970, as the threading model is already safe as designed.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-09-04T11:52:29.096Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 3932
File: Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs:48-55
Timestamp: 2025-09-04T11:52:29.096Z
Learning: In Flow Launcher's PluginsManifest.cs, when dealing with version parsing for the MinimumAppVersion feature, maintainer jjw24 prefers to keep the solution simple rather than implementing comprehensive helper methods for SemVer parsing normalization.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
🧬 Code graph analysis (1)
Flow.Launcher/ViewModel/MainViewModel.cs (5)
Flow.Launcher/Storage/TopMostRecord.cs (2)
FlowLauncherJsonStorageTopMostRecord(12-103)FlowLauncherJsonStorageTopMostRecord(17-77)Flow.Launcher/Storage/QueryHistory.cs (3)
History(11-119)Add(59-87)UpdateIcoPathAbsolute(105-118)Flow.Launcher/ViewModel/ResultsViewModel.cs (2)
List(227-238)List(240-261)Flow.Launcher/Storage/LastOpenedHistoryResult.cs (4)
LastOpenedHistoryResult(10-117)LastOpenedHistoryResult(26-28)LastOpenedHistoryResult(35-56)LastOpenedHistoryResult(63-93)Flow.Launcher.Core/Plugin/QueryBuilder.cs (1)
Query(9-61)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (10)
Flow.Launcher/Storage/QueryHistory.cs (4)
5-6: LGTM!The new using directives and type change to
List<LastOpenedHistoryResult>are necessary for the refactored history storage.Also applies to: 18-19
23-52: LGTM!The legacy migration correctly converts
HistoryItemobjects toLastOpenedHistoryResultinstances. SettingIcoPathandGlyphtonullis appropriate since legacy items lack this information, and theActionprovides reasonable fallback behavior.
89-97: LGTM!Clean helper method that properly delegates equality comparison to
LastOpenedHistoryResult.Equals.
99-118: LGTM!The method correctly handles edge cases: empty history, missing plugin IDs, and uninstalled plugins. The XML documentation clearly states the prerequisite that plugins must be initialized before calling.
Flow.Launcher/ViewModel/MainViewModel.cs (6)
49-50: LGTM!Field declaration and initialization reordering is appropriate for code organization.
Also applies to: 155-159
358-362: LGTM!Good fix for the potential
IndexOutOfRangeExceptionwhen history results are empty.
644-656: LGTM!Correctly updates the preview panel when returning to query results via Esc key, maintaining consistency with other navigation paths.
1327-1401: LGTM!The refactored
GetHistoryItemsmethod correctly:
- Orders by
ExecutedDateTimedescending before deduplication- Uses
GroupBywithFirst()to retain the most recent occurrence- Deep copies items to prevent mutation of stored data
- Clears
PluginIDon copies to prevent re-saving- Uses the original
item(notcopiedItem) in theAsyncActionfor accurate result populationThe fallback to re-query when
PopulateResultsAsyncreturns null is a good resilience pattern.
1404-1422: LGTM!Well-documented internal method with correct sequencing: legacy migration before icon path refresh. The XML remarks appropriately warn about the plugin initialization prerequisite.
1659-1672: LGTM!Correctly uses the new
selectLastparameter to limit history items displayed on the home page.
| copiedItem.Title = Localize.executeQuery(copiedItem.Query); | ||
| copiedItem.IcoPath = Constant.HistoryIcon; | ||
| // TODO: Add Glyph here | ||
| // copiedItem.Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C"); |
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 we should also copy Glyph here.
|
Don't have much time review these days:( |
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.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
Flow.Launcher/Helper/ResultHelper.cs
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Learnt from: NoPlagiarism
Repo: Flow-Launcher/Flow.Launcher PR: 3104
File: Flow.Launcher.Plugin/Result.cs:73-74
Timestamp: 2024-12-02T07:37:46.838Z
Learning: In 'Result.cs', the user prefers not to add additional data URI validation in the 'IcoPath' property setter.
📚 Learning: 2026-01-05T10:06:36.650Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Applied to files:
Flow.Launcher/Helper/ResultHelper.cs
📚 Learning: 2025-10-16T09:29:19.653Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3854
File: Flow.Launcher.Core/Plugin/PluginManager.cs:519-523
Timestamp: 2025-10-16T09:29:19.653Z
Learning: In Flow Launcher's PluginManager.cs QueryDialogJumpForPluginAsync method, when a DialogJump plugin is still initializing, returning null is intentional behavior. This allows the query to fall through to the default Explorer plugin, which serves as a fallback handler. This is different from QueryForPluginAsync and QueryHomeForPluginAsync, which show "still initializing" messages because they don't have fallback mechanisms.
Applied to files:
Flow.Launcher/Helper/ResultHelper.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (1)
Flow.Launcher/Helper/ResultHelper.cs (1)
14-17: LGTM!The signature update from
LastOpenedHistoryItemtoLastOpenedHistoryResultaligns with the PR's refactoring objectives, and the delegation pattern remains intact.
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.
Actionable comments posted: 0
🧹 Nitpick comments (3)
Flow.Launcher/ViewModel/MainViewModel.cs (1)
1352-1358: Consider copying the Glyph property.A past review comment suggested copying the
Glyphproperty for Query-style history. Currently, onlyIcoPathis set. If the original result had a glyph, it may be beneficial to preserve it in the copied item.🔎 Proposed addition
if (Settings.HistoryStyle == HistoryStyle.Query) { copiedItem.Title = Localize.executeQuery(copiedItem.Query); copiedItem.IcoPath = Constant.HistoryIcon; - // TODO: Add Glyph here - // copiedItem.Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C"); + copiedItem.Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C"); }Based on past review comments.
Flow.Launcher/Storage/QueryHistory.cs (2)
74-82: Consider updating Glyph alongside IcoPath.When updating an existing history item at lines 77-81, only
ExecutedDateTimeandIcoPathare refreshed. If the result'sGlyphproperty can also change over time (e.g., plugin updates), you may want to update it here as well for consistency.🔎 Proposed addition
if (LastOpenedHistoryItems.Count > 0 && TryGetLastOpenedHistoryResult(result, out var existingHistoryItem)) { existingHistoryItem.ExecutedDateTime = DateTime.Now; if (existingHistoryItem.IcoPath != result.IcoPath) { existingHistoryItem.IcoPath = result.IcoPath; } + if (existingHistoryItem.Glyph != result.Glyph) + { + existingHistoryItem.Glyph = result.Glyph; + } }Based on past review comments.
131-139: Consider logging when plugins are not found.When a history item references a
PluginIDthat no longer exists (line 135-136), the code silently continues. For troubleshooting and maintenance, it may be helpful to log a debug or warning message when a plugin cannot be resolved.🔎 Proposed addition
foreach (var item in LastOpenedHistoryItems) { if (string.IsNullOrEmpty(item.PluginID)) continue; var pluginPair = PluginManager.GetPluginForId(item.PluginID); - if (pluginPair == null) continue; + if (pluginPair == null) + { + App.API.LogDebug(nameof(History), $"Plugin {item.PluginID} not found for history item: {item.Title}"); + continue; + } item.PluginDirectory = pluginPair.Metadata.PluginDirectory; }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Flow.Launcher/Storage/QueryHistory.csFlow.Launcher/ViewModel/MainViewModel.cs
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Learnt from: NoPlagiarism
Repo: Flow-Launcher/Flow.Launcher PR: 3104
File: Flow.Launcher.Plugin/Result.cs:73-74
Timestamp: 2024-12-02T07:37:46.838Z
Learning: In 'Result.cs', the user prefers not to add additional data URI validation in the 'IcoPath' property setter.
📚 Learning: 2026-01-05T10:06:36.650Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Applied to files:
Flow.Launcher/Storage/QueryHistory.csFlow.Launcher/ViewModel/MainViewModel.cs
📚 Learning: 2024-11-03T07:40:11.014Z
Learnt from: Yusyuriv
Repo: Flow-Launcher/Flow.Launcher PR: 3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-10-16T10:48:30.573Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3854
File: Flow.Launcher/App.xaml.cs:252-275
Timestamp: 2025-10-16T10:48:30.573Z
Learning: In Flow Launcher's App.xaml.cs, the plugin initialization block (lines 252-275) that includes PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, _mainVM.QueryResults(), and API.SaveAppAllSettings() does not require additional Task.Run wrappers or Dispatcher.InvokeAsync calls according to maintainer Jack251970, as the threading model is already safe as designed.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-09-04T11:52:29.096Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 3932
File: Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs:48-55
Timestamp: 2025-09-04T11:52:29.096Z
Learning: In Flow Launcher's PluginsManifest.cs, when dealing with version parsing for the MinimumAppVersion feature, maintainer jjw24 prefers to keep the solution simple rather than implementing comprehensive helper methods for SemVer parsing normalization.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-05-01T05:38:25.673Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3500
File: Flow.Launcher/Storage/TopMostRecord.cs:145-149
Timestamp: 2025-05-01T05:38:25.673Z
Learning: For the MultipleTopMostRecord implementation in Flow.Launcher, sequence order of records in the ConcurrentBag does not need to be preserved, as confirmed by the developer. The unordered nature of ConcurrentBag is acceptable for this implementation.
Applied to files:
Flow.Launcher/ViewModel/MainViewModel.cs
🧬 Code graph analysis (2)
Flow.Launcher/Storage/QueryHistory.cs (3)
Flow.Launcher.Core/Plugin/PluginManager.cs (2)
PluginManager(24-1044)PluginManager(168-174)Flow.Launcher/Storage/LastOpenedHistoryResult.cs (5)
LastOpenedHistoryResult(10-117)LastOpenedHistoryResult(26-28)LastOpenedHistoryResult(35-56)LastOpenedHistoryResult(63-93)Equals(101-116)Flow.Launcher/Storage/HistoryItem.cs (1)
Obsolete(5-45)
Flow.Launcher/ViewModel/MainViewModel.cs (1)
Flow.Launcher.Core/Plugin/QueryBuilder.cs (1)
Query(9-61)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (2)
Flow.Launcher/ViewModel/MainViewModel.cs (2)
1407-1425: Well-designed helper method.The
RefreshLastOpenedHistoryResultsmethod is clear and well-documented. The remarks correctly note that plugins must be initialized before calling, which aligns with the startup sequence where this is invoked afterPluginManager.InitializePluginsAsync.
2-2: Remove the unusedusing System.Collections;directive.This namespace is not used in the file—only generic collections from
System.Collections.Genericare referenced.Likely an incorrect or invalid review comment.
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
Flow.Launcher/Storage/QueryHistory.cs (2)
73-82: Should Glyph also be updated here?When updating an existing history item, the code updates
IcoPathif it differs from the incoming result (lines 78-81), but doesn't updateGlyph. If the result's glyph has changed (e.g., plugin update, dynamic glyph logic), the history item will display stale glyph information.Consider also updating
Glyphto keep the visual representation consistent:🔎 Proposed enhancement to update Glyph
existingHistoryItem.ExecutedDateTime = DateTime.Now; if (existingHistoryItem.IcoPath != result.IcoPath) { existingHistoryItem.IcoPath = result.IcoPath; } +if (existingHistoryItem.Glyph != result.Glyph) +{ + existingHistoryItem.Glyph = result.Glyph; +}Based on past review comments.
100-109: Should Glyph also be updated here?Similar to the
Addmethod, when updating an existing history item'sIcoPath(lines 105-108), theGlyphproperty is not updated. For consistency and to keep visual representations current, consider updatingGlyphas well.🔎 Proposed enhancement to update Glyph
existingHistoryItem.ExecutedDateTime = DateTime.Now; if (existingHistoryItem.IcoPath != result.IcoPath) { existingHistoryItem.IcoPath = result.IcoPath; } +if (existingHistoryItem.Glyph != result.Glyph) +{ + existingHistoryItem.Glyph = result.Glyph; +}Based on past review comments.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
Flow.Launcher/Storage/QueryHistory.cs
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Learnt from: NoPlagiarism
Repo: Flow-Launcher/Flow.Launcher PR: 3104
File: Flow.Launcher.Plugin/Result.cs:73-74
Timestamp: 2024-12-02T07:37:46.838Z
Learning: In 'Result.cs', the user prefers not to add additional data URI validation in the 'IcoPath' property setter.
📚 Learning: 2026-01-05T10:06:36.650Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2026-01-06T07:16:42.908Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Helper/ResultHelper.cs:27-27
Timestamp: 2026-01-06T07:16:42.908Z
Learning: In Flow.Launcher/Helper/ResultHelper.cs, PopulateResultsAsync uses PluginManager.QueryForPluginAsync instead of direct plugin.Plugin.QueryAsync to handle plugin initialization gracefully. When a plugin is still initializing, QueryForPluginAsync returns a fake "still loading" result that won't match historical records, causing PopulateResultsAsync to return null. This is intentional and preferred over directly querying uninitialized plugins, which could produce unpredictable behavior.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2024-11-03T07:40:11.014Z
Learnt from: Yusyuriv
Repo: Flow-Launcher/Flow.Launcher PR: 3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-10-16T10:48:30.573Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3854
File: Flow.Launcher/App.xaml.cs:252-275
Timestamp: 2025-10-16T10:48:30.573Z
Learning: In Flow Launcher's App.xaml.cs, the plugin initialization block (lines 252-275) that includes PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, _mainVM.QueryResults(), and API.SaveAppAllSettings() does not require additional Task.Run wrappers or Dispatcher.InvokeAsync calls according to maintainer Jack251970, as the threading model is already safe as designed.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-09-04T11:52:29.096Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 3932
File: Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs:48-55
Timestamp: 2025-09-04T11:52:29.096Z
Learning: In Flow Launcher's PluginsManifest.cs, when dealing with version parsing for the MinimumAppVersion feature, maintainer jjw24 prefers to keep the solution simple rather than implementing comprehensive helper methods for SemVer parsing normalization.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
🧬 Code graph analysis (1)
Flow.Launcher/Storage/QueryHistory.cs (2)
Flow.Launcher/ViewModel/MainViewModel.cs (4)
List(1327-1405)Query(1207-1235)Result(1810-1851)Result(1853-1881)Flow.Launcher/Storage/LastOpenedHistoryResult.cs (5)
LastOpenedHistoryResult(10-117)LastOpenedHistoryResult(26-28)LastOpenedHistoryResult(35-56)LastOpenedHistoryResult(63-93)Equals(101-116)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (6)
Flow.Launcher/Storage/QueryHistory.cs (6)
5-6: LGTM - Necessary imports for new functionality.The added using directives support PluginManager access in
UpdateIcoPathAbsolute()and localization in the migration code.
19-19: LGTM - Type migration is consistent with PR objectives.The change from
LastOpenedHistoryItemtoLastOpenedHistoryResultaligns with the goal of using Result-based history items to preserve properties and display icons.
23-28: LGTM - Clear migration documentation.The XML documentation and Obsolete attribute clearly communicate the migration purpose and deprecation timeline.
35-49: LGTM - Migration logic correctly handles legacy data.The migration code appropriately converts legacy history items to the new format, setting up query-style entries with actions to re-run the original query. The absence of PluginID is intentional since legacy items represent historical queries rather than specific plugin results.
112-120: LGTM - Clean try-get pattern implementation.The helper method cleanly encapsulates the logic to find matching history items, relying on
LastOpenedHistoryResult.Equals(Result)for comparison semantics.
122-141: LGTM - Proper icon path refresh logic.The
UpdateIcoPathAbsolute()method correctly refreshes icon paths for history items by updating theirPluginDirectorybased on current plugin metadata. The null checks and PluginID validation ensure safe execution, and the XML remarks appropriately document the timing requirement (call after plugins are loaded).
| if (string.IsNullOrEmpty(copiedItem.IcoPath)) // Must manually set missing image icon here | ||
| { | ||
| Title = Localize.executeQuery(h.Query), | ||
| SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime), | ||
| IcoPath = Constant.HistoryIcon, | ||
| OriginQuery = new Query { TrimmedQuery = h.Query }, | ||
| Action = _ => | ||
| { | ||
| App.API.BackToQueryResults(); | ||
| App.API.ChangeQuery(h.Query); | ||
| return false; | ||
| }, | ||
| Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") | ||
| }; | ||
| results.Add(result); | ||
| copiedItem.IcoPath = Constant.MissingImgIcon; |
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.
IcoPath shouldn't be null, this should not be necessary. If you just add the default IcoPath and Glyph as history icon when calling the PopulateHistoryFromLegacyHistory then you don't need to assign them here. Why are you setting the default IcoPath in PopulateHistoryFromLegacyHistory as null?
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 you are getting the missing image icon during testing like in one of your screenshots is because you are testing with History.json from dev branch after it has been migrated by the previous PR. This means when you try this PR PopulateHistoryFromLegacyHistory is not called and consequently IcoPath is not set (because the code doesn't need to set it for normal results).
You need to test with History.json from prod build or as a fresh build where History.json doesn't exist.
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.
IcoPath shouldn't be null, this should not be necessary. If you just add the default IcoPath and Glyph as history icon when calling the PopulateHistoryFromLegacyHistory then you don't need to assign them here. Why are you setting the default IcoPath in PopulateHistoryFromLegacyHistory as null?
I think setting IcoPath to history icon path is unnecessary since this path is accessible in codes and we can use a if sentence to set the history icon
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 you are getting the missing image icon during testing like in one of your screenshots is because you are testing with History.json from dev branch after it has been migrated by the previous PR. This means when you try this PR PopulateHistoryFromLegacyHistory is not called and consequently IcoPath is not set (because the code doesn't need to set it for normal results).
You need to test with History.json from prod build or as a fresh build where History.json doesn't exist.
I think if we do not know the actual icon for some history items, we should use this missing icon instead of the history icon as the default icon under Last Opened Mode.
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.
Since the badge icon is already the history icon...
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.
Setting by default where it is loaded is better than putting in if statement, I think the correct use of if here is set a different value 'if the required property (such as SubTitle) needs to be different than the source'.
Sorry, I do not agree with you. The path saved locally is static, while the path in the code is dynamic and runtime. If we change this path from Images\history.png to Images\history_icon.png, will the old path of that history icon still work? But the path from codes should always be right.
We should know the actual icon though, because LastOpenHistoryResult is a child class of Result, so unless Result doesn't for some reason have IcoPath assigned, in this case if I remember correctly if IcoPath is null or pointing to a non-existent image then code later on will assign missing icon image by default anyway.
Yes, LastOpenHistoryResult should know the actual icons. But if we set a static history icon as the icon paths of those old data, the badge icons will be the same as the icons.
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 IcoPath should store its actual icons
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.
Sorry, I do not agree with you. The path saved locally is static, while the path in the code is dynamic and runtime. If we change this path from Images\history.png to Images\history_icon.png, will the old path of that history icon still work? But the path from codes should always be right.
Well, it will still work because in my code with PopulateHistoryFromLegacyHistory we set IcoPath = Constant.HistoryIcon,, dynamically assigned on startup.
You are setting null for IcoPath in PopulateHistoryFromLegacyHistory then add a specific if statement to handle this null with if (string.IsNullOrEmpty(copiedItem.IcoPath)) (Line 1354), I think is not required especially for a throw away backwards compatibility method that only gets run once. Legacy history results that we migrated for the user will always have the history icon and new history results will always contain a non-null IcoPath, so why do we need to handle IcoPath null? Have I missed a scenario?
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.
Sorry, I do not agree with you. The path saved locally is static, while the path in the code is dynamic and runtime. If we change this path from Images\history.png to Images\history_icon.png, will the old path of that history icon still work? But the path from codes should always be right.
Well, it will still work because in my code with PopulateHistoryFromLegacyHistory we set
IcoPath = Constant.HistoryIcon,, dynamically assigned on startup.You are setting null for IcoPath in PopulateHistoryFromLegacyHistory then add a specific if statement to handle this null with
if (string.IsNullOrEmpty(copiedItem.IcoPath))(Line 1354), I think is not required especially for a throw away backwards compatibility method that only gets run once. Legacy history results that we migrated for the user will always have the history icon and new history results will always contain a non-null IcoPath, so why do we need to handle IcoPath null? Have I missed a scenario?
Well, feel free to make any changes for this
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.
Sorry, I do not agree with you. The path saved locally is static, while the path in the code is dynamic and runtime. If we change this path from Images\history.png to Images\history_icon.png, will the old path of that history icon still work? But the path from codes should always be right.
Well, it will still work because in my code with PopulateHistoryFromLegacyHistory we set
IcoPath = Constant.HistoryIcon,, dynamically assigned on startup.You are setting null for IcoPath in PopulateHistoryFromLegacyHistory then add a specific if statement to handle this null with
if (string.IsNullOrEmpty(copiedItem.IcoPath))(Line 1354), I think is not required especially for a throw away backwards compatibility method that only gets run once. Legacy history results that we migrated for the user will always have the history icon and new history results will always contain a non-null IcoPath, so why do we need to handle IcoPath null? Have I missed a scenario?
Well, feel free to make any changes for this
Homepage display takes into consideration of result selection ranking, the behavior is, when on fresh boot the result is ordered descending by date, and then they move up the more you select them. Is this not the case? |
Oh yeah. I forgot the user selection score |
| /// <summary> | ||
| /// Update a result into the last-opened history list (<see cref="LastOpenedHistoryItems"/>). | ||
| /// </summary> | ||
| public void Update(Result result) |
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.
What scenario do we need this for? This is pretty much the same as the add method.
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.
What scenario do we need this for? This is pretty much the same as the add method.
When we are executing one command from history item itself.
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.
hm, I am aware that when you select a result from the history page or I think also home page it doesn't call Add(), I thought this was by design as selecting history results don't count towards user selection like normal acutal results do. However, changing this looks like introducing a little bit of unnecessary complexity in the code.
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.
hm, I am aware that when you select a result from the history page or I think also home page it doesn't call
Add(), I thought this was by design as selecting history results don't count towards user selection like normal acutal results do. However, changing this looks like introducing a little bit of unnecessary complexity in the code.
I think this logic is necessary since it keeps the icon & execute date up-to-date. And in codes, we also handle the user select record, right?
if (reflectResult != null)
{
// Record the user selected record for result ranking
_userSelectedRecord.Add(reflectResult);
// Update the history with the reflected result (I think it is necessary)
_history.Update(reflectResult);
// Since some actions may need to hide the Flow window to execute
// So let us populate the results of them
return await reflectResult.ExecuteAsync(c);
}
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.
If you think it is unnecessary, let us remove them all.
// Record the user selected record for result ranking
_userSelectedRecord.Add(reflectResult);
// Update the history with the reflected result (I think it is necessary)
_history.Update(reflectResult);
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.
Reverted as you said
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.
Actionable comments posted: 1
🤖 Fix all issues with AI Agents
In @Flow.Launcher/Storage/QueryHistory.cs:
- Around line 74-82: In the block that updates an existing history item (where
LastOpenedHistoryItems.Count > 0 and TryGetLastOpenedHistoryResult(result, out
var existingHistoryItem) returns true), also compare and assign
existingHistoryItem.Glyph to result.Glyph when they differ (just like you do for
IcoPath), in addition to updating existingHistoryItem.ExecutedDateTime and
existingHistoryItem.IcoPath; update the Glyph check/assignment alongside the
IcoPath check to ensure the glyph is kept in sync with result.Glyph.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Flow.Launcher/Storage/QueryHistory.csFlow.Launcher/ViewModel/MainViewModel.cs
🚧 Files skipped from review as they are similar to previous changes (1)
- Flow.Launcher/ViewModel/MainViewModel.cs
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
📚 Learning: 2026-01-05T10:06:36.650Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:36.650Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2026-01-06T07:16:42.908Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Helper/ResultHelper.cs:27-27
Timestamp: 2026-01-06T07:16:42.908Z
Learning: In Flow.Launcher/Helper/ResultHelper.cs, PopulateResultsAsync uses PluginManager.QueryForPluginAsync instead of direct plugin.Plugin.QueryAsync to handle plugin initialization gracefully. When a plugin is still initializing, QueryForPluginAsync returns a fake "still loading" result that won't match historical records, causing PopulateResultsAsync to return null. This is intentional and preferred over directly querying uninitialized plugins, which could produce unpredictable behavior.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2024-11-03T07:40:11.014Z
Learnt from: Yusyuriv
Repo: Flow-Launcher/Flow.Launcher PR: 3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-10-16T10:48:30.573Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3854
File: Flow.Launcher/App.xaml.cs:252-275
Timestamp: 2025-10-16T10:48:30.573Z
Learning: In Flow Launcher's App.xaml.cs, the plugin initialization block (lines 252-275) that includes PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, _mainVM.QueryResults(), and API.SaveAppAllSettings() does not require additional Task.Run wrappers or Dispatcher.InvokeAsync calls according to maintainer Jack251970, as the threading model is already safe as designed.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-09-04T11:52:29.096Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 3932
File: Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs:48-55
Timestamp: 2025-09-04T11:52:29.096Z
Learning: In Flow Launcher's PluginsManifest.cs, when dealing with version parsing for the MinimumAppVersion feature, maintainer jjw24 prefers to keep the solution simple rather than implementing comprehensive helper methods for SemVer parsing normalization.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (5)
Flow.Launcher/Storage/QueryHistory.cs (5)
5-6: LGTM!The new using directives are necessary for
PluginManager.GetPluginForId(line 113) andLocalize.executeQuery(line 37).
19-19: LGTM!The type change from
LastOpenedHistoryItemtoLastOpenedHistoryResultaligns with the PR objective to inherit fromResultand retain Result properties.
23-52: LGTM!The legacy migration correctly creates
LastOpenedHistoryResultinstances withIcoPathandGlyphset to null (appropriate since legacy data doesn't contain this information), and the Action lambda properly restores the historical query.
89-97: LGTM!The helper method correctly uses
FirstOrDefaultwithEqualsto locate matching history items. The O(n) scan is acceptable given the 300-item max history size, and the pattern relies on theLastOpenedHistoryResult.Equalsimplementation to define matching semantics.
99-118: LGTM!The method correctly refreshes icon paths by updating
PluginDirectoryfor each history item (which in turn triggersIcoPathAbsoluterecalculation inLastOpenedHistoryResult). The null checks and early returns are appropriate, and the remarks clearly state this should be called after plugin initialization.
Jack251970
left a comment
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.
Changes
| LastOpenedHistoryItems.Add(new LastOpenedHistoryResult | ||
| { | ||
| Title = Localize.executeQuery(item.Query), | ||
| IcoPath = null, |
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.
Set it to null and parse it during runtime
|
|
||
| if (selected != null) // SelectedItem returns null if selection is empty. | ||
| if (selected != null && // SelectedItem returns null if selection is empty. | ||
| !string.IsNullOrEmpty(selected.PluginID)) // SelectedItem must have a valid PluginID |
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.
Check item plugin ID
| } | ||
|
|
||
| private List<Result> GetHistoryItems(IEnumerable<LastOpenedHistoryItem> historyItems) | ||
| private List<Result> GetHistoryItems(IEnumerable<LastOpenedHistoryResult> historyItems, int? selectLast = null) |
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.
Add selectLast parameter for querying history results in home page
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.
What is this for?
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.
For fixing issues when querying history items in home page. I unified the its querying logic
| { | ||
| var result = new Result | ||
| copiedItem.Title = Localize.executeQuery(copiedItem.Query); | ||
| copiedItem.IcoPath = Constant.HistoryIcon; |
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.
Use history icon under Query History Mode
| } | ||
| else | ||
| { | ||
| if (string.IsNullOrEmpty(copiedItem.IcoPath)) // Must manually set missing image icon here |
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.
Use actual icon + history icon badge icon under Last Opened Mode
| } | ||
| // Since some actions may need to hide the Flow window to execute | ||
| // So let us populate the results of them | ||
| return await reflectResult.ExecuteAsync(c); |
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.
Do not record the user selected record for result ranking
|
|
||
| var results = GetHistoryItems(historyItems); | ||
| // Select last history results | ||
| var results = GetHistoryItems(_history.LastOpenedHistoryItems, Settings.MaxHistoryResultsToShowForHomePage); |
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.
Combine get history item for home page logic into GetHistoryItems
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @Flow.Launcher/Storage/LastOpenedHistoryResult.cs:
- Around line 130-145: The Equals(Result r) method can throw a
NullReferenceException when r or r.OriginQuery is null because it accesses
r.OriginQuery.TrimmedQuery; update Equals to first validate r is not null and
guard access to r.OriginQuery (e.g., check r == null and r.OriginQuery == null)
before reading TrimmedQuery, and then either return false when missing or throw
ArgumentNullException for fail-fast behavior; ensure all comparisons that use
OriginQuery.TrimmedQuery (both branches) reference the guarded/nullable-safe
value and keep comparisons for RecordKey, Title, SubTitle, PluginID and Query
unchanged.
🧹 Nitpick comments (2)
Flow.Launcher/Storage/QueryHistory.cs (2)
65-68: Off-by-one in max history enforcement.Using
> _maxHistoryallows the list to grow to 301 items before removal. If the intent is to keep at most 300 items, consider using>=.Suggested fix
- if (LastOpenedHistoryItems.Count > _maxHistory) + if (LastOpenedHistoryItems.Count >= _maxHistory) { LastOpenedHistoryItems.RemoveAt(0); }
71-72: Redundant count check.The
LastOpenedHistoryItems.Count > 0guard is unnecessary sinceTryGetLastOpenedHistoryResultusesFirstOrDefault, which safely returnsnullon an empty list.Simplified condition
- if (LastOpenedHistoryItems.Count > 0 && - TryGetLastOpenedHistoryResult(result, out var existingHistoryItem)) + if (TryGetLastOpenedHistoryResult(result, out var existingHistoryItem))
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
Flow.Launcher/Storage/LastOpenedHistoryResult.csFlow.Launcher/Storage/QueryHistory.csFlow.Launcher/ViewModel/MainViewModel.cs
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:46.190Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
📚 Learning: 2026-01-05T10:06:46.190Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Storage/LastOpenedHistoryResult.cs:35-56
Timestamp: 2026-01-05T10:06:46.190Z
Learning: In Flow.Launcher/Storage/LastOpenedHistoryResult.cs, the LastOpenedHistoryResult(Result result) constructor should not add null checks for result or result.OriginQuery - the maintainer prefers fail-fast behavior where invalid inputs cause immediate exceptions.
Applied to files:
Flow.Launcher/Storage/LastOpenedHistoryResult.csFlow.Launcher/ViewModel/MainViewModel.csFlow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2026-01-06T07:16:50.302Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 4057
File: Flow.Launcher/Helper/ResultHelper.cs:27-27
Timestamp: 2026-01-06T07:16:50.302Z
Learning: In Flow.Launcher/Helper/ResultHelper.cs, PopulateResultsAsync uses PluginManager.QueryForPluginAsync instead of direct plugin.Plugin.QueryAsync to handle plugin initialization gracefully. When a plugin is still initializing, QueryForPluginAsync returns a fake "still loading" result that won't match historical records, causing PopulateResultsAsync to return null. This is intentional and preferred over directly querying uninitialized plugins, which could produce unpredictable behavior.
Applied to files:
Flow.Launcher/Storage/LastOpenedHistoryResult.csFlow.Launcher/ViewModel/MainViewModel.csFlow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2024-12-08T21:12:12.060Z
Learnt from: Yusyuriv
Repo: Flow-Launcher/Flow.Launcher PR: 3118
File: Flow.Launcher/ViewModel/MainViewModel.cs:1404-1413
Timestamp: 2024-12-08T21:12:12.060Z
Learning: In the `MainViewModel` class, the `_lastQuery` field is initialized in the constructor and is never null.
Applied to files:
Flow.Launcher/ViewModel/MainViewModel.cs
📚 Learning: 2024-12-02T07:37:46.838Z
Learnt from: NoPlagiarism
Repo: Flow-Launcher/Flow.Launcher PR: 3104
File: Flow.Launcher.Plugin/Result.cs:73-74
Timestamp: 2024-12-02T07:37:46.838Z
Learning: In 'Result.cs', the user prefers not to add additional data URI validation in the 'IcoPath' property setter.
Applied to files:
Flow.Launcher/ViewModel/MainViewModel.cs
📚 Learning: 2025-05-01T05:38:25.673Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3500
File: Flow.Launcher/Storage/TopMostRecord.cs:145-149
Timestamp: 2025-05-01T05:38:25.673Z
Learning: For the MultipleTopMostRecord implementation in Flow.Launcher, sequence order of records in the ConcurrentBag does not need to be preserved, as confirmed by the developer. The unordered nature of ConcurrentBag is acceptable for this implementation.
Applied to files:
Flow.Launcher/ViewModel/MainViewModel.cs
📚 Learning: 2024-11-03T07:40:11.014Z
Learnt from: Yusyuriv
Repo: Flow-Launcher/Flow.Launcher PR: 3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-10-16T10:48:30.573Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3854
File: Flow.Launcher/App.xaml.cs:252-275
Timestamp: 2025-10-16T10:48:30.573Z
Learning: In Flow Launcher's App.xaml.cs, the plugin initialization block (lines 252-275) that includes PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, _mainVM.QueryResults(), and API.SaveAppAllSettings() does not require additional Task.Run wrappers or Dispatcher.InvokeAsync calls according to maintainer Jack251970, as the threading model is already safe as designed.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-09-04T11:52:29.096Z
Learnt from: jjw24
Repo: Flow-Launcher/Flow.Launcher PR: 3932
File: Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs:48-55
Timestamp: 2025-09-04T11:52:29.096Z
Learning: In Flow Launcher's PluginsManifest.cs, when dealing with version parsing for the MinimumAppVersion feature, maintainer jjw24 prefers to keep the solution simple rather than implementing comprehensive helper methods for SemVer parsing normalization.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
📚 Learning: 2025-07-21T09:19:49.684Z
Learnt from: Jack251970
Repo: Flow-Launcher/Flow.Launcher PR: 3854
File: Flow.Launcher/App.xaml.cs:246-262
Timestamp: 2025-07-21T09:19:49.684Z
Learning: In Flow Launcher's App.xaml.cs, the asynchronous plugin initialization task (containing AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, and AutoPluginUpdates) does not require additional try-catch error handling according to maintainer Jack251970, as these operations are designed to handle exceptions internally.
Applied to files:
Flow.Launcher/Storage/QueryHistory.cs
🧬 Code graph analysis (2)
Flow.Launcher/Storage/LastOpenedHistoryResult.cs (1)
Flow.Launcher.Plugin/Result.cs (2)
Result(15-406)Result(324-358)
Flow.Launcher/Storage/QueryHistory.cs (2)
Flow.Launcher/ViewModel/MainViewModel.cs (5)
List(1319-1368)Query(1209-1237)BackToQueryResults(660-666)Result(1773-1814)Result(1816-1844)Flow.Launcher/Storage/LastOpenedHistoryResult.cs (5)
LastOpenedHistoryResult(11-146)LastOpenedHistoryResult(27-29)LastOpenedHistoryResult(36-57)LastOpenedHistoryResult(65-122)Equals(130-145)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (19)
Flow.Launcher/Storage/QueryHistory.cs (5)
5-5: LGTM!The new import is required for
PluginManager.GetPluginForIdused inUpdateIcoPathAbsolute.
17-18: LGTM!The type change to
List<LastOpenedHistoryResult>properly reflects the migration from the oldLastOpenedHistoryItemclass, enabling Result properties to be retained directly.
22-49: LGTM!The legacy migration logic correctly:
- Documents the deprecation timeline with
[Obsolete]attribute.- Maps legacy
HistoryItemfields toLastOpenedHistoryResult.- Properly captures
item.Queryin the Action delegate closure.Note that missing fields (IcoPath, PluginID, etc.) are intentionally left as defaults since legacy history didn't store this data.
86-94: LGTM!The
TryGetpattern is implemented correctly, leveragingLastOpenedHistoryResult.Equals(Result)for matching history items.
96-115: LGTM!The method correctly refreshes
PluginDirectoryfrom current plugin metadata, enabling accurateIcoPathAbsolutecomputation when Flow is moved. The null check at line 111 properly handles cases where a plugin may have been uninstalled.Flow.Launcher/Storage/LastOpenedHistoryResult.cs (6)
1-12: LGTM!Clean imports, file-scoped namespace, and clear XML documentation explaining the class purpose and inheritance relationship.
13-22: LGTM!Properties are well-documented with sensible defaults for serialization scenarios.
24-29: LGTM!Parameterless constructor required for JSON deserialization.
36-57: LGTM!Constructor properly copies essential fields and sets up the query history reopening action. The fail-fast approach (no null checks) aligns with maintainer preferences. Based on learnings.
95-122: LGTM with minor observation.The deep copy correctly captures values for closures and configures history-style properties. The minimal
Queryobject creation (line 103) is consistent with howEqualsuses it.
100-101: This comment is based on incorrect assumptions. The code intentionally setsPluginID = string.Emptyfor history results, and the codebase already has defensive guards in place to prevent context menu operations for items with empty PluginID (see MainViewModel.cs lines 438 and 1264). No exceptions occur from empty PluginID—the design explicitly prevents context menu operations in such cases with the checks!string.IsNullOrEmpty(SelectedResults.SelectedItem.Result.PluginID)and!string.IsNullOrEmpty(selected.PluginID).Likely an incorrect or invalid review comment.
Flow.Launcher/ViewModel/MainViewModel.cs (8)
48-50: LGTM!Storage field declarations look correct.
357-361: LGTM!Properly ensures the first history item is selected when switching to history mode, addressing the scrolling/highlighting issue mentioned in the PR objectives.
437-448: LGTM!The PluginID check correctly prevents context menu exceptions for history items that lack a valid PluginID, and the preview update ensures proper state when returning from context menu. This addresses the context menu exception discussed in the PR.
648-653: LGTM!Consistent preview state update when escaping back to Results view.
1263-1268: LGTM on the PluginID validation.The check
!string.IsNullOrEmpty(selected.PluginID)properly guards context menu operations for history items that lack a valid PluginID.
1319-1368: LGTM on the history deduplication and async action logic.The implementation correctly:
- Orders by
ExecutedDateTimedescending to show most recent first- Deduplicates LastOpened style by composite key (Title, SubTitle, PluginID, RecordKey) - addressing the duplicate history issue from PR discussion
- Uses the original
itemin the async closure forPopulateResultsAsyncto preserve unmodified propertiesOne minor observation: The grouping key includes
PluginIDwhich may be null/empty for some history items, but this is acceptable as they'll correctly group together by null/empty value.
1370-1388: LGTM!Well-documented method with clear prerequisites. The XML documentation properly notes that plugins must be initialized before calling this method for icon resolution to work correctly.
1625-1629: LGTM!Correctly passes the
MaxHistoryResultsToShowForHomePagesetting to limit history results on the home page.




Context:
Display icon on last history results
Follows on with #4042
Changes:
Before

After

Tested