Skip to content

Add internal model for plugin management #3572

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

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from

Conversation

Jack251970
Copy link
Member

@Jack251970 Jack251970 commented May 22, 2025

Add internal model for plugin management

Let us do not rely Plugin Manager plugin for plugin management in Flow Launcher. Flow Launcher will get into a very bad state if this plugin is deleted (plugin store page will lose ability to install/uninstall/update plugins).

Resolve #3555, #3236.

Additionally, now we support to select local zip file to install in Plugin Store page.

Test

  • Install/Uninstall/Update plugins
  • Install plugin from local path in Plugin Store page
image image

@Jack251970 Jack251970 linked an issue May 22, 2025 that may be closed by this pull request
2 tasks
@Jack251970 Jack251970 requested a review from Copilot May 22, 2025 09:36

This comment has been minimized.

Copy link

gitstream-cm bot commented May 22, 2025

🥷 Code experts: onesounds

onesounds has most 👩‍💻 activity in the files.
Jack251970, onesounds have most 🧠 knowledge in the files.

See details

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Activity based on git-commit:

onesounds
MAY 2 additions & 2 deletions
APR 104 additions & 38 deletions
MAR 10 additions & 0 deletions
FEB
JAN
DEC

Knowledge based on git-blame:
Jack251970: 26%
onesounds: 21%

Flow.Launcher/Languages/en.xaml

Activity based on git-commit:

onesounds
MAY 15 additions & 2 deletions
APR 45 additions & 23 deletions
MAR 8 additions & 3 deletions
FEB
JAN
DEC

Knowledge based on git-blame:
onesounds: 43%
Jack251970: 11%

Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml

Activity based on git-commit:

onesounds
MAY
APR 130 additions & 69 deletions
MAR 43 additions & 62 deletions
FEB
JAN
DEC

Knowledge based on git-blame:
onesounds: 62%
Jack251970: 13%

Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs

Activity based on git-commit:

onesounds
MAY
APR
MAR
FEB
JAN
DEC

Knowledge based on git-blame:
onesounds: 36%

Flow.Launcher/ViewModel/PluginViewModel.cs

Activity based on git-commit:

onesounds
MAY
APR
MAR 13 additions & 1 deletions
FEB
JAN
DEC

Knowledge based on git-blame:
Jack251970: 43%

To learn more about /:\ gitStream - Visit our Docs

Copy link

gitstream-cm bot commented May 22, 2025

Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces an internal model for plugin management to remove the dependency on the external Plugin Manager plugin, thereby preventing Flow Launcher from entering a bad state when that plugin is deleted.

  • Refactored the deletion command in PluginViewModel to use an internal uninstall method.
  • Updated PluginStoreItemViewModel with new async methods for installing, uninstalling, and updating plugins, and refactored plugin properties.
  • Added a new user setting with corresponding UI and language translation keys for automatically restarting Flow Launcher after plugin changes.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Flow.Launcher/ViewModel/PluginViewModel.cs Removed PluginManagerActionKeyword and updated delete plugin command to use the internal model.
Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs Refactored plugin data handling and introduced async plugin management methods (install, uninstall, update).
Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml Added a card to toggle the new auto restart setting.
Flow.Launcher/Languages/en.xaml Added new translation keys for plugin management messages and auto restart functionality.
Flow.Launcher/Infrastructure/UserSettings/Settings.cs Introduced a new AutoRestartAfterChanging setting.
Comments suppressed due to low confidence (1)

Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs:26

  • [nitpick] Consider renaming '_newPlugin' to 'currentPlugin' and '_oldPluginPair' to 'installedPluginPair' for clearer understanding.
            _newPlugin = plugin;

@Jack251970 Jack251970 added this to the Future milestone May 22, 2025
@Jack251970 Jack251970 added the bug Something isn't working label May 22, 2025
Co-authored-by: Copilot <[email protected]>
Copy link
Contributor

coderabbitai bot commented May 22, 2025

📝 Walkthrough

"""

Walkthrough

This update introduces an "Auto Restart After Changing" option to user settings and the general settings UI, along with corresponding localization resources. It significantly refactors the plugin store item view model to support robust, asynchronous plugin install, uninstall, and update workflows, addressing potential null reference exceptions and improving error handling.

Changes

Files/Paths Change Summary
Flow.Launcher.Infrastructure/UserSettings/Settings.cs Added two boolean properties: AutoRestartAfterChanging (default false) and ShowUnknownSourceWarning (default true).
Flow.Launcher/Languages/en.xaml Added new localization strings for plugin management actions, auto-restart option, confirmation prompts, warnings, error messages, and success messages related to plugin install, uninstall, update, and restart behaviors.
Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml Added a new card group with toggle switches for AutoRestartAfterChanging and ShowUnknownSourceWarning in the general settings UI, including icons and tooltips.
Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs Refactored to use separate readonly fields for new and existing plugins; updated properties accordingly; converted plugin install/uninstall/update commands to asynchronous methods invoking new async PluginManager methods with user prompts and progress.
Flow.Launcher/ViewModel/PluginViewModel.cs Removed unused static property; renamed and converted OpenDeletePluginWindow to asynchronous OpenDeletePluginWindowAsync calling the new async uninstall method.
Flow.Launcher.Core/Plugin/PluginManager.cs Added asynchronous methods for installing, uninstalling, and updating plugins with user confirmation dialogs, progress reporting, cancellation support, error handling, and conditional auto-restart logic; added internal async file download helper.
Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs Added InstallPluginAsync command to select a plugin ZIP file via dialog and install it asynchronously using PluginManager.
Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml Added a new button bound to InstallPluginCommand to trigger local plugin installation via UI.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SettingsPane
    participant Settings
    User->>SettingsPane: Toggles "Auto Restart After Changing"
    SettingsPane->>Settings: Updates AutoRestartAfterChanging property
Loading
sequenceDiagram
    participant User
    participant PluginStoreUI
    participant PluginStoreItemViewModel
    participant PluginManager

    User->>PluginStoreUI: Clicks Install/Uninstall/Update Plugin
    PluginStoreUI->>PluginStoreItemViewModel: ShowCommandQueryAsync(action)
    PluginStoreItemViewModel->>User: Show confirmation dialog
    User-->>PluginStoreItemViewModel: Confirms
    PluginStoreItemViewModel->>PluginManager: Call async Install/Uninstall/Update method
    PluginManager->>User: Show progress and handle cancellation
    PluginManager->>PluginStoreItemViewModel: Return success/failure
    PluginStoreItemViewModel->>User: Show result message or prompt restart
Loading

Assessment against linked issues

Objective Addressed Explanation
Fix NullReferenceException in PluginStoreItemViewModel (#3555)

Suggested labels

enhancement

Suggested reviewers

  • jjw24
  • taooceros

Poem

A toggle to restart, with a hop and a wink,
Plugins now update in a whisker’s blink.
Async flows and prompts, so neat and so new,
No more nulls to chase, just carrots to chew!
Flow Launcher leaps on, with code fresh and bright—
Bugs in the burrow, but features in sight!
🥕
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs (1)

160-197: Mirror the ‘restart-on-error’ fix in Uninstall flow

Same unconditional restart occurs here. Insert an early return inside catch, or capture a success flag shared with the final block.

🧹 Nitpick comments (3)
Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs (3)

119-137: Partial download artefact not cleaned when user cancels

When the user presses “Cancel” in the progress box the temp zip (possibly half-written) is left on disk, and the next install run deletes only if deleteFile is true and the filename collides. Consider explicit cleanup on cancellation:

if (cts.IsCancellationRequested)
{
-    return;
+    if (!newPlugin.IsFromLocalInstallPath && File.Exists(filePath))
+        File.Delete(filePath);
+    return;
}

199-254: Update flow: stale zip file not deleted after successful update

UpdatePluginAsync downloads to %TEMP% but never deletes the zip afterwards (unlike install). This can quickly clutter %TEMP% with large archives.

@@
                 else
                 {
                     await App.API.UpdatePluginAsync(oldPlugin, newPlugin, filePath);
+                    if (!newPlugin.IsFromLocalInstallPath && File.Exists(filePath))
+                        File.Delete(filePath);
                 }

256-289: Download helper: typo and double-download logic

  1. Comment line 269 spells “expcetion”.
  2. When the progress box fails, we silently fall back to a background download without progress or user feedback. Confirm this is desired UX; otherwise surface the error.

Consider surfacing the original exception to the caller instead of a silent retry.

🧰 Tools
🪛 GitHub Check: Check Spelling

[warning] 264-264:
prg is not a recognized word. (unrecognized-spelling)

🪛 GitHub Actions: Check Spelling

[warning] 264-264: Spell check warning: prg is not a recognized word. (unrecognized-spelling)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac61469 and 949344a.

📒 Files selected for processing (5)
  • Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1 hunks)
  • Flow.Launcher/Languages/en.xaml (2 hunks)
  • Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml (1 hunks)
  • Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs (3 hunks)
  • Flow.Launcher/ViewModel/PluginViewModel.cs (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: Check Spelling
Flow.Launcher/ViewModel/PluginViewModel.cs

[warning] 17-17: Spell check warning: Ioc is not a recognized word. (unrecognized-spelling)

Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs

[warning] 19-19: Spell check warning: Ioc is not a recognized word. (unrecognized-spelling)


[warning] 264-264: Spell check warning: prg is not a recognized word. (unrecognized-spelling)

🪛 GitHub Check: Check Spelling
Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs

[warning] 19-19:
Ioc is not a recognized word. (unrecognized-spelling)


[warning] 264-264:
prg is not a recognized word. (unrecognized-spelling)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: gitStream workflow automation
  • GitHub Check: gitStream workflow automation
  • GitHub Check: gitStream.cm
  • GitHub Check: gitStream.cm
  • GitHub Check: build
🔇 Additional comments (7)
Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1)

179-179: Good addition of the auto-restart setting

The new AutoRestartAfterChanging property with a default value of false is a good addition that will help control the application's restart behavior after plugin changes.

Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml (1)

205-214: Well-structured UI control for auto-restart setting

The toggle switch for the auto-restart setting is properly implemented with:

  • Appropriate binding to the Settings.AutoRestartAfterChanging property
  • Localized title and tooltip
  • Consistent styling with other toggle switches
  • Good positioning in the settings hierarchy

This follows the established pattern for settings controls in the application.

Flow.Launcher/ViewModel/PluginViewModel.cs (2)

1-1: Appropriate addition of Task namespace

The addition of the System.Threading.Tasks namespace is necessary for the async implementation.


173-175: Good conversion to async uninstall method

Converting the plugin uninstall operation to an asynchronous method is a good improvement that:

  1. Properly uses async/await pattern
  2. Leverages the centralized uninstall method from PluginStoreItemViewModel
  3. Supports the PR objective of creating an internal model for plugin management

This change will make the plugin uninstallation process more robust.

Flow.Launcher/Languages/en.xaml (2)

134-135: Well-defined localization strings for auto-restart setting

The localization strings for the auto-restart feature are clear and descriptive, explaining both the purpose of the setting and its effects.


189-204: Comprehensive localization for plugin management

This set of localization strings provides thorough coverage for the plugin management workflow:

  • Error messages for installation/uninstallation/updating failures
  • Success messages with restart instructions
  • Confirmation prompts with plugin details
  • Settings preservation options
  • Download progress indicators

These strings will ensure a good user experience with appropriate feedback throughout the plugin management process.

Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs (1)

98-106: Generated filename may contain invalid path characters

newPlugin.Name can legally contain : or other characters invalid on Windows, making Path.Combine throw.
Sanitise the name (use Path.GetInvalidFileNameChars()) before composing the filename.

This comment has been minimized.

@Jack251970 Jack251970 requested a review from Copilot May 22, 2025 09:41

This comment has been minimized.

Copilot

This comment was marked as outdated.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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/PluginStoreItemViewModel.cs (1)

32-33: Version parsing remains a potential exception source.

This addresses a previous review concern about new Version(string) throwing exceptions on malformed version strings. The issue persists in the current implementation.

Consider using safe version parsing to prevent UI crashes:

-        public bool LabelUpdate => LabelInstalled && new Version(_newPlugin.Version) > new Version(_oldPluginPair.Metadata.Version);
+        public bool LabelUpdate => LabelInstalled && TryParseVersionComparison(_newPlugin.Version, _oldPluginPair.Metadata.Version);
+        
+        private static bool TryParseVersionComparison(string newVersion, string oldVersion)
+        {
+            return Version.TryParse(newVersion, out var newVer) && 
+                   Version.TryParse(oldVersion, out var oldVer) && 
+                   newVer > oldVer;
+        }
🧹 Nitpick comments (1)
Flow.Launcher.Core/Plugin/PluginManager.cs (1)

871-904: Fix spelling issues in parameter name and comment.

The download helper method is well-designed with progress reporting and retry logic, but has spelling issues flagged by static analysis.

Apply this diff to fix the spelling issues:

-        internal static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
+        internal static async Task DownloadFileAsync(string progressBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
         {
             if (deleteFile && File.Exists(filePath))
                 File.Delete(filePath);
 
             if (showProgress)
             {
                 var exceptionHappened = false;
-                await API.ShowProgressBoxAsync(prgBoxTitle,
+                await API.ShowProgressBoxAsync(progressBoxTitle,
                     async (reportProgress) =>
                     {
                         if (reportProgress == null)
                         {
-                            // when reportProgress is null, it means there is expcetion with the progress box
+                            // when reportProgress is null, it means there is exception with the progress box
                             // so we record it with exceptionHappened and return so that progress box will close instantly
                             exceptionHappened = true;
                             return;
🧰 Tools
🪛 GitHub Check: Check Spelling

[warning] 879-879:
prg is not a recognized word. (unrecognized-spelling)

🪛 GitHub Actions: Check Spelling

[warning] 879-883: prg is not a recognized word. (unrecognized-spelling)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76736b7 and 383c0ae.

📒 Files selected for processing (3)
  • Flow.Launcher.Core/Plugin/PluginManager.cs (4 hunks)
  • Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs (4 hunks)
  • Flow.Launcher/ViewModel/PluginViewModel.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Flow.Launcher/ViewModel/PluginViewModel.cs
🧰 Additional context used
🧬 Code Graph Analysis (1)
Flow.Launcher.Core/Plugin/PluginManager.cs (5)
Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1)
  • Settings (16-478)
Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs (1)
  • UserPlugin (62-80)
Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs (8)
  • GetTranslation (136-136)
  • MessageBoxResult (366-366)
  • InstallPlugin (511-511)
  • LogException (276-276)
  • ShowMsgError (85-85)
  • RestartApp (34-34)
  • ShowMsg (114-114)
  • ShowMsg (123-123)
Flow.Launcher.Core/Resource/Internationalization.cs (1)
  • GetTranslation (247-259)
Flow.Launcher.Plugin/PluginMetadata.cs (1)
  • PluginMetadata (10-163)
🪛 GitHub Check: Check Spelling
Flow.Launcher.Core/Plugin/PluginManager.cs

[warning] 879-879:
prg is not a recognized word. (unrecognized-spelling)

🪛 GitHub Actions: Check Spelling
Flow.Launcher.Core/Plugin/PluginManager.cs

[warning] 39-53: Ioc is not a recognized word. (unrecognized-spelling)


[warning] 117-133: Reloadable is not a recognized word. (unrecognized-spelling)


[warning] 179-183: metadatas is not a recognized word. (unrecognized-spelling)


[warning] 181-185: metadatas is not a recognized word. (unrecognized-spelling)


[warning] 182-186: metadatas is not a recognized word. (unrecognized-spelling)


[warning] 184-188: metadatas is not a recognized word. (unrecognized-spelling)


[warning] 879-883: prg is not a recognized word. (unrecognized-spelling)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (6)
Flow.Launcher.Core/Plugin/PluginManager.cs (4)

28-28: LGTM: FlowSettings integration looks good.

The static field retrieval of Settings via IoC is appropriate here since PluginManager is a static class and the settings are used for runtime behavior control.


553-624: Excellent async plugin installation with comprehensive user experience.

The method provides:

  • User confirmation before proceeding
  • Progress reporting during download with cancellation support
  • Proper error handling with early return on failure (prevents unwanted restart)
  • Conditional restart based on user settings
  • Clean file management for temporary downloads

626-664: Well-implemented uninstall flow with proper user choices.

The method correctly:

  • Confirms the uninstall action with the user
  • Provides choice for keeping/removing plugin settings
  • Handles errors gracefully without restarting on failure
  • Follows consistent UX pattern with other plugin operations

666-722: Robust update implementation following established patterns.

The update flow properly handles the two-plugin scenario (old and new) and maintains consistency with install/uninstall operations regarding user confirmation, error handling, and restart behavior.

Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs (2)

12-18: Excellent refactoring improves code clarity and separation of concerns.

The split into _newPlugin and _oldPluginPair fields makes the code more readable and eliminates repeated lookups. The constructor properly initializes both fields for consistent state.


63-79: Async conversion successfully integrates with new plugin management workflow.

The method correctly dispatches to the appropriate async PluginManager methods based on the action. The developer has chosen to keep the default case minimal as noted in past reviews.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

Copy link

github-actions bot commented Jun 9, 2025

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

❌ Errors and Warnings Count
❌ forbidden-pattern 22
⚠️ non-alpha-in-dictionary 13

See ❌ Event descriptions for more information.

If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (5)
Flow.Launcher.Core/Plugin/PluginManager.cs (4)

564-635: Well-structured install method with comprehensive user interaction.

The method properly handles user confirmation, downloads, installation, and restart flow. The error handling ensures graceful failure without unwanted restarts.

Some minor suggestions for improvement:

-                var downloadFilename = string.IsNullOrEmpty(newPlugin.Version)
-                    ? $"{newPlugin.Name}-{Guid.NewGuid()}.zip"
-                    : $"{newPlugin.Name}-{newPlugin.Version}.zip";
+                var downloadFilename = string.IsNullOrWhiteSpace(newPlugin.Version)
+                    ? $"{newPlugin.Name}-{Guid.NewGuid()}.zip"
+                    : $"{newPlugin.Name}-{newPlugin.Version}.zip";

Consider using IsNullOrWhiteSpace for more robust empty string detection.


642-646: Simplify plugin.json extraction logic.

The current implementation has redundant code for getting the plugin.json entry.

Apply this diff to streamline the logic:

-                var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json") ??
-                    throw new FileNotFoundException("The zip file does not contain a plugin.json file.");
-                var pluginJsonEntry = archive.GetEntry(pluginJsonPath.ToString()) ??
-                    throw new FileNotFoundException("The zip file does not contain a plugin.json file.");
+                var pluginJsonEntry = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json") ??
+                    throw new FileNotFoundException("The zip file does not contain a plugin.json file.");

918-951: Fix typos and improve error handling.

The download helper has good retry logic but contains typos and could benefit from clearer documentation.

Apply these fixes:

-        internal static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
+        internal static async Task DownloadFileAsync(string progressBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
-                await API.ShowProgressBoxAsync(prgBoxTitle,
+                await API.ShowProgressBoxAsync(progressBoxTitle,
-                            // when reportProgress is null, it means there is expcetion with the progress box
+                            // when reportProgress is null, it means there is exception with the progress box
🧰 Tools
🪛 GitHub Check: Check Spelling

[warning] 926-926:
prg is not a recognized word. (unrecognized-spelling)


953-969: Enhance URL validation robustness.

The InstallSourceKnown method should handle edge cases more gracefully.

Consider this improvement:

 private static bool InstallSourceKnown(string url)
 {
+    if (string.IsNullOrWhiteSpace(url))
+        return false;
+        
     var pieces = url.Split('/');

     if (pieces.Length < 4)
         return false;

     var author = pieces[3];
     var acceptedSource = "https://github.com";
     var constructedUrlPart = string.Format("{0}/{1}/", acceptedSource, author);

     return url.StartsWith(acceptedSource) &&
         API.GetAllPlugins().Any(x =>
             !string.IsNullOrEmpty(x.Metadata.Website) &&
             x.Metadata.Website.StartsWith(constructedUrlPart)
         );
 }
Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs (1)

113-130: Improve cross-platform compatibility and error handling.

The file dialog helper has some platform-specific assumptions that could be improved.

Consider these improvements:

 private static string GetFileFromDialog(string title, string filter = "")
 {
+    var downloadsPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+    try
+    {
+        downloadsPath = Path.Combine(downloadsPath, "Downloads");
+    }
+    catch
+    {
+        // Fallback to user profile if Downloads folder access fails
+    }
+    
     var dlg = new OpenFileDialog
     {
-        InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\Downloads",
+        InitialDirectory = downloadsPath,
         Multiselect = false,
         CheckFileExists = true,
         CheckPathExists = true,
         Title = title,
         Filter = filter
     };

     return dlg.ShowDialog() switch
     {
         DialogResult.OK => dlg.FileName,
         _ => string.Empty
     };
 }

This approach:

  • Uses Path.Combine for better cross-platform support
  • Adds error handling for Downloads folder access
  • Maintains the same functionality while being more robust
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6bf7f00 and 248b098.

📒 Files selected for processing (5)
  • Flow.Launcher.Core/Plugin/PluginManager.cs (4 hunks)
  • Flow.Launcher/Languages/en.xaml (2 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs (2 hunks)
  • Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml (1 hunks)
  • Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
  • Flow.Launcher/Languages/en.xaml
🧰 Additional context used
🧬 Code Graph Analysis (1)
Flow.Launcher.Core/Plugin/PluginManager.cs (7)
Flow.Launcher/PublicAPIInstance.cs (12)
  • Task (121-121)
  • Task (215-234)
  • Task (247-248)
  • Task (250-251)
  • Task (253-254)
  • GetTranslation (240-240)
  • MessageBoxResult (470-473)
  • InstallPlugin (540-541)
  • LogException (276-277)
  • ShowMsgError (123-124)
  • ShowMsg (126-127)
  • ShowMsg (129-132)
Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1)
  • Settings (16-494)
Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs (1)
  • UserPlugin (62-80)
Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs (8)
  • GetTranslation (141-141)
  • MessageBoxResult (371-371)
  • InstallPlugin (516-516)
  • LogException (281-281)
  • ShowMsgError (85-85)
  • RestartApp (34-34)
  • ShowMsg (119-119)
  • ShowMsg (128-128)
Flow.Launcher.Core/Resource/Internationalization.cs (1)
  • GetTranslation (247-259)
Flow.Launcher.Plugin/PluginMetadata.cs (2)
  • ToString (159-162)
  • PluginMetadata (10-163)
Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs (1)
  • InstallSourceKnown (581-597)
🪛 GitHub Check: Check Spelling
Flow.Launcher.Core/Plugin/PluginManager.cs

[warning] 926-926:
prg is not a recognized word. (unrecognized-spelling)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: gitStream.cm
  • GitHub Check: build
🔇 Additional comments (8)
Flow.Launcher.Core/Plugin/PluginManager.cs (5)

5-5: LGTM! Appropriate new imports added.

The new using statements for System.IO.Compression and System.Windows are correctly added to support zip file handling and MessageBox operations in the new plugin management methods.

Also applies to: 10-10


29-29: LGTM! Clean integration with user settings.

The FlowSettings field provides proper access to user configuration for controlling auto-restart behavior and warning preferences.


660-668: LGTM! Proper unknown source validation.

The security check for unknown plugin sources with user warning is well-implemented. The conditional check based on settings provides good user control.


673-711: Excellent uninstall workflow with user choice preservation.

The method properly handles user confirmation for both uninstall and settings retention. The error handling prevents restart on failure.


713-769: Well-implemented update method with proper flow control.

The update workflow correctly handles confirmation, download, and restart logic. Good consistency with other plugin management methods.

Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml (1)

95-101: LGTM! Well-integrated install button.

The new button is properly positioned in the toolbar, has appropriate command binding to InstallPluginCommand, and includes a helpful tooltip. The styling is consistent with other buttons in the interface.

Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs (2)

1-2: LGTM! Appropriate using statements added.

The new imports are correctly added to support the file dialog functionality and plugin manager integration.

Also applies to: 5-5, 7-7


102-111: LGTM! Clean command implementation.

The InstallPluginAsync method is well-structured with proper async handling and delegates to the PluginManager for the actual work.

@Jack251970 Jack251970 requested a review from Copilot June 9, 2025 12:33
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR replaces the external Plugin Manager plugin with an internal model, adds install/uninstall/update flows (including local zip installs), and introduces new UI controls and settings for plugin management.

  • Added async install/uninstall/update methods with optional auto-restart and warnings in PluginManager.
  • Updated ViewModels to call the new internal API and added a local-zip install command.
  • Extended settings UI with toggles for auto-restart after plugin changes and warnings for unknown sources.

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Flow.Launcher/ViewModel/PluginViewModel.cs Switched delete action to use PluginManager.UninstallPluginAndCheckRestartAsync and removed the old keyword helper.
Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs Replaced flyout keyword logic with async install/uninstall/update switch.
Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml Added a button to install a plugin from a local zip.
Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml Added toggle switches for auto-restart and unknown source warnings.
Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs Introduced OpenFileDialog logic and InstallPluginCommand.
Flow.Launcher/Languages/en.xaml Added translation strings for install/uninstall/update prompts and new settings.
Flow.Launcher.Infrastructure/UserSettings/Settings.cs Added AutoRestartAfterChanging and ShowUnknownSourceWarning settings.
Flow.Launcher.Core/Plugin/PluginManager.cs Implemented internal plugin install/uninstall/update flows, file downloads, and helper methods.
Comments suppressed due to low confidence (2)

Flow.Launcher/ViewModel/PluginViewModel.cs:173

  • [nitpick] The method name OpenDeletePluginWindowAsync does not reflect that it actually uninstalls the plugin and may restart the app. Consider renaming to UninstallPluginAsync or similar for clarity.
private async Task OpenDeletePluginWindowAsync()

Flow.Launcher/Languages/en.xaml:206

  • [nitpick] Translation key AutoRestartAfterChange is inconsistent with code’s autoRestartAfterChanging property and other keys. Consider unifying the naming convention for clarity.
<system:String x:Key="AutoRestartAfterChange">Automatically restart after installing/uninstalling/updating plugins in plugin store</system:String>

await PluginManager.InstallPluginAndCheckRestartAsync(file);
}

private static string GetFileFromDialog(string title, string filter = "")
Copy link
Preview

Copilot AI Jun 9, 2025

Choose a reason for hiding this comment

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

[nitpick] This viewmodel directly uses System.Windows.Forms.OpenFileDialog, introducing a WinForms dependency into WPF. Consider using Microsoft.Win32.OpenFileDialog or abstracting the file picker behind an interface.

Copilot uses AI. Check for mistakes.

Copy link
Member Author

Choose a reason for hiding this comment

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

no need

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
20 min review bug Something isn't working
Projects
None yet
1 participant