Skip to content
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

Add plugin table view #280

Merged
merged 15 commits into from
Jan 9, 2025
Merged

Add plugin table view #280

merged 15 commits into from
Jan 9, 2025

Conversation

DropSnorz
Copy link
Owner

@DropSnorz DropSnorz commented Dec 3, 2024

Related to #270

  • Add Plugin Table UI component
  • Refactor PluginsController to support Table / TreeView
  • Configure table columns and add scanDirectoryPath property
  • Bind search and filtering operation on plugin table
  • Implement table contextual menu
  • Refactor confirmation dialog for plugin actions (disable, uninstall, ...)
  • Update plugin selection logic to support active display
  • Set a default plugin display when app starts
  • Fix table style issues (borders, background with no items)
  • Review and cleanup

Copy link

coderabbitai bot commented Dec 3, 2024

Walkthrough

The pull request introduces significant refactoring and enhancement of the plugin management system in the OwlPlug client application. The changes focus on improving the user interface, plugin discovery, and management processes. Key modifications include renaming variables for clarity, adding new controllers for plugin tree and table views, updating plugin file collection and creation logic, and restructuring the plugin display and interaction mechanisms. Additionally, new utility methods are introduced for file handling, and the dialog management system is restructured for better organization.

Changes

File/Path Change Summary
ApplicationDefaults.java Renamed rootDirectoryImage to scanDirectoryImage and added PLUGIN_PREFERRED_DISPLAY_KEY.
CoreTaskFactory.java Added PluginService dependency and updated createFileStatSyncTask method to use pluginService for directory gathering.
PluginInfoController.java Updated handling of the plugin variable and integrated logic for enabling/disabling plugins.
PluginTableController.java New controller for managing plugin table view with filtering capabilities.
PluginTreeViewController.java New controller for managing plugin tree view with advanced filtering.
PluginsController.java Significant UI and functionality updates, added new view controllers and improved search/filtering.
Plugin.java Added scanDirectoryPath field and related getter/setter methods; removed specific constructor.
PluginService.java Renamed method to getPrimaryPluginPathByFormat and added getDirectoriesExplorationSet().
Plugin Discovery Files Standardized plugin creation logic across different file format handlers, utilizing createPlugin() method.
FileUtils.java Added utility methods for retrieving parent directory name and file name.
PluginsView.fxml Restructured UI layout with new tabs and containers for improved user experience.
DialogManager.java Removed overloaded newDialog methods; updated to use DialogLayout.
AbstractDialogController.java Updated to use getLayout() method returning DialogLayout.
Various Dialog Controllers Updated to use getLayout() method for dialog content management.

Sequence Diagram

sequenceDiagram
    participant User
    participant PluginsController
    participant PluginTreeViewController
    participant PluginTableController
    participant PluginService
    participant PluginFileCollector

    User->>PluginsController: Interact with Plugins View
    PluginsController->>PluginService: Get Directories Exploration Set
    PluginService-->>PluginsController: Return Directories
    PluginsController->>PluginFileCollector: Collect Plugin Files
    PluginFileCollector-->>PluginsController: Return Plugin Files
    PluginsController->>PluginTreeViewController: Set Plugins
    PluginsController->>PluginTableController: Set Plugins
    PluginTreeViewController->>PluginTreeViewController: Generate Tree View
    PluginTableController->>PluginTableController: Generate Table View
    User->>PluginsController: Search/Filter Plugins
    PluginsController->>PluginTreeViewController: Apply Filter
    PluginsController->>PluginTableController: Apply Filter
Loading

Finishing Touches

  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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 or @coderabbitai title 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.

@DropSnorz DropSnorz self-assigned this Dec 30, 2024
@DropSnorz
Copy link
Owner Author

@coderabbitai review

Copy link

coderabbitai bot commented Jan 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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: 1

🧹 Nitpick comments (25)
owlplug-client/src/main/java/com/owlplug/core/controllers/PluginInfoController.java (2)

141-141: Maintain consistent approach for refreshing.

You call pluginsController.refresh() here and in other areas. Ensure consistent usage of either refresh() or displayPlugins() if they share similar behavior, or clarify if each method serves a different purpose.


286-286: Combine plugin disable logic with a unified refresh flow.

After disabling the plugin, calling pluginsController.refresh() ensures the UI stays in sync. If multiple refresh calls happen frequently, consider centralizing them in a single method or using an event-based approach.

owlplug-client/src/main/java/com/owlplug/core/ui/PluginTreeCell.java (1)

141-141: Ensure naming clarity for the new image reference.

Replacing rootDirectoryImage with scanDirectoryImage may potentially cause confusion if it’s still intended to represent the “root” icon. Consider renaming the resource to better reflect its usage context if you’d like to preserve semantic clarity, for example, rootScanDirectoryImage or similar.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Vst3BundleFile.java (1)

55-56: Consider adding documentation for the createPlugin method.

While the refactoring improves the code structure, it would be helpful to document the responsibilities of the createPlugin() method in the parent class.

Add Javadoc to explain the plugin creation process:

+  /**
+   * Creates a new Plugin instance with common properties initialized.
+   * Subclasses should call this method and then set format-specific properties.
+   * @return A new Plugin instance
+   */
   protected Plugin createPlugin() {
owlplug-client/src/main/java/com/owlplug/explore/services/ExploreService.java (1)

280-280: Clarify multi-format handling.
Here, the code unconditionally returns the path associated with the first enabled format in the bundle. If there are multiple enabled formats, the chosen path may be arbitrary and might not align with user expectations. Consider providing clear user feedback or a strategy for choosing which format’s path to use.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Lv2BundleFile.java (1)

57-58: Well-structured plugin format handling architecture!

The refactoring aligns well with several design patterns and principles:

  • Template Method Pattern for plugin creation
  • DRY principle by centralizing common initialization
  • Clean separation of concerns between different plugin formats
  • Extensible design for adding new plugin formats
owlplug-client/src/main/java/com/owlplug/core/components/CoreTaskFactory.java (1)

52-53: Consider marking pluginService as final.
If it is only set during construction and it is never reassigned, marking it as final could help ensure immutability and clarity in the code.

- @Autowired
- private PluginService pluginService;
+ @Autowired
+ private final PluginService pluginService;
owlplug-client/src/main/resources/fxml/PluginsView.fxml (3)

20-30: Consider adopting a dedicated container or styling approach for the top bar spacing.
The HBox layout and nested elements look good, but if you plan to expand the top bar, an external style or a dedicated CSS might improve maintainability.


31-49: Add user-friendly tooltips to the export and sync buttons.
Although the icons and button text provide some context, tooltips can further enhance user accessibility, especially for internationalization or quick hints.


60-60: TabPane location and side alignment.
This TabPane is anchored to the left side, which is an interesting UI choice. Verify this location is intentional and aligns with the overall UX design.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (3)

53-56: Consider constructor-based injection or using final fields
By injecting PluginTreeViewController and PluginTableController via fields, testing might be slightly more cumbersome. Using constructor-based injection or marking these fields as final can improve testability and clarity of dependencies.


182-185: Handle empty or invalid plugin sets
In displayPlugins, you iterate over the plugins to set them in both controllers. Consider how this behaves if the plugin set is empty or if pluginDAO.findAll() returns null. Adding defensive checks or logs might prevent unforeseen runtime errors.


197-204: Consider centralizing info pane toggling logic
setInfoPaneDisplay and toggleInfoPaneDisplay replicate visibility changes. Maintaining separate methods for each toggling variant can lead to confusion or duplication. Consider combining or carefully documenting them for clarity.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTreeViewController.java (2)

57-57: Rename or document the search property
The SimpleStringProperty search field is straightforward, but a more descriptive name or Javadoc can clarify its purpose (e.g., searchFilter). This would help future maintainers quickly identify its function.


81-111: Check performance and consistency of filtering
You bind predicates twice (for the plugin tree and the file tree). For large sets of plugins, real-time filtering could cause delays. Consider caching search terms or throttling updates if latency becomes an issue.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/PluginFile.java (2)

45-45: Use a fallback for empty file name when deriving plugin name.

If this.getPluginFile().getName() is empty, removeExtension might result in an unexpected empty string. You might consider a fallback approach to ensure a valid plugin name.


63-65: Expose scanDirectory carefully or consider returning a path string.

Returning a File reference might encourage direct file manipulation from outside this class. Use caution or consider returning a string path to maintain consistent usage with the rest of the code.

owlplug-client/src/main/java/com/owlplug/core/model/Plugin.java (1)

106-113: Consider enforcing consistent path usage.

Ensure that scanDirectoryPath always stores converted or sanitized paths to avoid backslash vs. slash inconsistencies.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java (6)

58-78: Refine the Format Column Setup
You are creating a custom TableCell<Plugin, PluginFormat> to display format icons. This approach works well, but consider whether you need fallback text or an error icon if getPluginFormatIcon returns null. This could improve resilience if the icon is missing or the format is unrecognized.


87-102: Directory Column: Potential Null Handling
When constructing the directory column, consider that FileUtils.getParentDirectoryName(...) might return null in edge cases (e.g., plugin path is empty). You handle it downstream in the cell factory by checking whether the item is null, but verifying potential null returns earlier could make the code more robust.


121-135: Plugin State Column: Variation Handling
The custom cell for plugin states sets only a PluginStateView graphic. For debugging or textual representation, you might also include a text label or fallback text to clarify the plugin’s state if the icon doesn’t load or fails to display properly.


137-138: Order of Columns
You add columns in the order: format, name, version, manufacturer, category, directory, scan directory, then state. Ensure this order aligns with the user’s desired workflow (e.g., possibly name first, then format?).


140-152: Filtering Logic
The FilteredList predicate matches on plugin name and category. You might want to extend it to also check for matches on manufacturer or other attributes. This can improve discoverability for users searching by partial manufacturer names. Additionally, consider trimming the search string for whitespace.


160-162: Potential Encapsulation Concern
getTableView() directly exposes the internal TableView. If you need to preserve encapsulation, consider providing only the necessary operations (e.g., selection model or refresh) instead of returning the entire control.

owlplug-client/src/main/java/com/owlplug/core/services/PluginService.java (1)

185-210: Modularize Directory Discovery
The new getDirectoriesExplorationSet() method improves readability by consolidating the logic for assembling directory paths. Just ensure the code references only valid or non-empty returns from getPreferences(), and that directorySet does not end up containing blank strings.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between de1cc4c and 174a42c.

📒 Files selected for processing (22)
  • owlplug-client/src/main/java/com/owlplug/core/components/ApplicationDefaults.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/components/CoreTaskFactory.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginInfoController.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTreeViewController.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/model/Plugin.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/services/PluginService.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/PluginFileCollector.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/AuComponentFile.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Lv2BundleFile.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/OsxVstFile.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/PluginFile.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/SoVstFile.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Vst3BundleFile.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Vst3DllFile.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/VstDllFile.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/ui/PluginStateView.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/ui/PluginTreeCell.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/utils/FileUtils.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/explore/services/ExploreService.java (2 hunks)
  • owlplug-client/src/main/resources/fxml/PluginsView.fxml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • owlplug-client/src/main/java/com/owlplug/core/components/ApplicationDefaults.java
🔇 Additional comments (30)
owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/AuComponentFile.java (1)

40-41: Great use of the new createPlugin() method and explicit format setting.

The code looks concise and more modular. However, ensure any previous logic around the disabled state (if still needed) is properly handled or placed in a dedicated utility method. Otherwise, no immediate issues are detected.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/SoVstFile.java (1)

27-28: Ensure the disabled state is preserved.

The code sets the plugin format to VST2 but no longer sets the plugin as disabled if the file ends with .disabled. Verify that createPlugin() handles the .disabled suffix properly so the plugin's disabled state is accurately represented if needed.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginInfoController.java (2)

133-133: Confirm concurrency safety for refresh operations.

Check that pluginsController.refresh() is thread-safe or always invoked on the JavaFX Application Thread. In general, UI updates and controller interactions should be done via Platform.runLater() if the task isn't already executing on the correct thread.


239-239: Check for UI synchronization after removing plugin.

Switching from clearAndFillPluginTree() to displayPlugins() may alter the user experience. Ensure it sufficiently updates both the plugin tree view and any other relevant views, maintaining a seamless UI experience.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Vst3BundleFile.java (1)

55-56: LGTM! Good refactoring to improve modularity.

The extraction of plugin creation logic into createPlugin() improves code maintainability and ensures consistent plugin instantiation across different format handlers.

Let's verify the disabled state handling in the parent class:

✅ Verification successful

Disabled state handling is properly managed in the parent class

The verification shows that the disabled state is correctly handled in the parent class PluginFile.java. The createPlugin() method in PluginFile sets the disabled state by calling plugin.setDisabled(this.isDisabled()), where isDisabled() checks if the file path ends with ".disabled". This means the removal of the direct disabled state setting in Vst3BundleFile is correct as it's now handled by the parent class.

The codebase shows a complete disabled state management system:

  • PluginFile handles the initial state during plugin creation
  • PluginService manages enable/disable operations with file renaming
  • UI components (PluginTreeCell, PluginInfoController) properly reflect the disabled state
  • The state is considered in plugin operations (PluginSyncTask)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if disabled state is handled in the parent class or other format handlers
# Expected: Find disabled state handling in PluginFile.java or createPlugin implementation

# Search for disabled state handling in parent class
ast-grep --pattern 'class PluginFile {
  $$$
  createPlugin() {
    $$$
    setDisabled($$$)
    $$$
  }
  $$$
}'

# Search for disabled state references
rg "setDisabled|isDisabled" -A 5

Length of output: 7162

owlplug-client/src/main/java/com/owlplug/explore/services/ExploreService.java (1)

260-260: Double-check for potential null or empty path return.
If getPrimaryPluginPathByFormat(format) can return null or an empty string when no valid path is found, it could cause runtime errors (e.g., NullPointerException) or unexpected behavior in the subsequent logic that checks path equality. Consider validating the returned path or logging a warning if it’s null or empty.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Lv2BundleFile.java (1)

57-58: Clean refactoring of plugin creation logic!

The change simplifies the plugin creation process by leveraging the parent class's createPlugin() method, which promotes code reuse and consistency across different plugin format handlers.

Let's verify that no LV2-specific initialization was lost in this refactoring:

✅ Verification successful

Refactoring verified - No LV2-specific initialization was lost

After reviewing the complete implementation, I can confirm that the refactoring is safe and correct. Here's why:

  • The parent PluginFile.createPlugin() handles all the common initialization (path, name, disabled status)
  • The Lv2BundleFile class maintains its LV2-specific functionality in the toComponents() method, which is responsible for parsing the LV2 manifest and creating plugin components
  • Setting the format after plugin creation is appropriate as it's a simple property assignment that doesn't affect other initialization

The changes successfully separate common plugin initialization into the parent class while preserving the LV2-specific component handling in the dedicated method.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any LV2-specific plugin initialization in the codebase
# and verify the base createPlugin() implementation

# Check the parent class implementation
ast-grep --pattern 'class PluginFile {
  $$$
  createPlugin() {
    $$$
  }
  $$$
}'

# Look for any LV2-specific initialization patterns in the old code
git log -p -- owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Lv2BundleFile.java | rg -A 5 'toPlugin\(\)'

Length of output: 86


Script:

#!/bin/bash
# Let's try a different approach to find the relevant code

# Find the parent class implementation
fd "PluginFile.java" --exec cat {}

# Find the current implementation of Lv2BundleFile
fd "Lv2BundleFile.java" --exec cat {}

# Look for any other LV2-specific classes that might contain initialization logic
rg -l "LV2" --type java

Length of output: 6021

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/Vst3DllFile.java (1)

46-47: Check plugin name consistency and error handling

Great job on consolidating plugin creation into createPlugin() and explicitly setting the format to VST3. However, please ensure that the createPlugin() method properly infers and sets the plugin’s name from the file name (and removes the *.vst3 extension if needed). Also confirm that it gracefully handles any possible file or path anomalies in upstream code.

You can run the following script to review all references to createPlugin() and verify that the plugin name is being handled consistently:

✅ Verification successful

Let me gather more information about the plugin name handling.


Plugin name handling is properly implemented

The verification shows that plugin name handling is correctly implemented in the base PluginFile class. The createPlugin() method in PluginFile.java properly sets the plugin name by removing the file extension from the plugin file name using FilenameUtils.removeExtension(this.getPluginFile().getName()). This ensures consistent name handling across all plugin types (VST3, VST2, AU, etc.) since they all inherit from this base class.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Searching for the createPlugin() method usage and verifying any naming logic across the codebase.

ast-grep --pattern $'createPlugin() { $$$ }'
rg -A 3 "createPlugin"

Length of output: 11373


Script:

#!/bin/bash
# Let's examine the base PluginFile class implementation and any name-related logic

# First, check the base PluginFile class
ast-grep --pattern 'class PluginFile { $$$ }'

# Then look for any name-related methods or properties
rg -A 5 "getName|setName" "owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/"

Length of output: 2428

owlplug-client/src/main/java/com/owlplug/core/components/CoreTaskFactory.java (2)

27-27: Good introduction of the PluginService import.
It cleanly segregates directory exploration logic into a dedicated service.


129-129: Validate the returned set for potential edge cases.
If pluginService.getDirectoriesExplorationSet() returns an empty set or null, consider handling that scenario more explicitly. You could log a warning or gracefully skip synchronization if no directories are available.

owlplug-client/src/main/resources/fxml/PluginsView.fxml (4)

17-18: Use caution if imports are not actually leveraged.
These imports are added, but there is no direct usage of FilteredTableView or Pane in the FXML. If they're not used in the final design, consider removing them to keep the file tidy.


50-55: Validate dynamic population of pluginsContainer.
Ensure appropriate controllers or logic inject plugin items into this VBox. If the population logic is handled elsewhere, verify it’s properly bound.


62-64: Great use of multiple tabs to organize plugin listings.
Having separate tabs for List, Directories, and Table can make the UI more user-friendly.


73-77: Ensure consistent sizing and styling in pluginInfoPane.
Since this pane is resizable, confirm that layout constraints and dynamic UI elements (e.g., the included NodeInfoView.fxml) behave as expected on various window sizes.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (2)

90-92: Ensure error handling for null or missing UI nodes
You are directly adding the tree and table to the pluginsContainer. If these FXML fields are missing or uninitialized, it could cause runtime issues. Consider a quick null-check or exception guard to guarantee safe addition in all scenarios.


130-130: Verify search behavior for special characters
tableController.searchProperty().bind(searchTextField.textProperty()); ensures real-time filtering. If users enter special or non-ASCII characters, verify the search logic handles them gracefully (e.g., case sensitivity, partial matches, etc.).

owlplug-client/src/main/java/com/owlplug/core/ui/PluginStateView.java (1)

15-17: Constructor addition looks good
The new constructor cleanly delegates to setPluginState, promoting code reuse and maintainability.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/VstDllFile.java (1)

46-47: Plugin format setting
The updated toPlugin method cleanly calls createPlugin() then sets PluginFormat.VST2. This straightforward approach follows best practices.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/OsxVstFile.java (1)

50-51: Centralized plugin creation is a good refactor
Transitioning to createPlugin() for instantiation simplifies the code and ensures consistent initialization, including the VST2 format.

owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/fileformats/PluginFile.java (2)

33-33: Good addition for metadata tracking.

Storing the directory location helps contextualize the file for further processing, such as building relative paths.


41-49: Validate scanDirectory existence prior to usage.

In createPlugin(), the code uses this.getScanDirectory().getAbsolutePath(). If scanDirectory is null, this will throw a NullPointerException.

Consider adding a null check:

 Plugin createPlugin() {
-  plugin.setScanDirectoryPath(FileUtils.convertPath(this.getScanDirectory().getAbsolutePath()));
+  if (this.getScanDirectory() != null) {
+    plugin.setScanDirectoryPath(FileUtils.convertPath(this.getScanDirectory().getAbsolutePath()));
+  }
   ...
 }
owlplug-client/src/main/java/com/owlplug/core/tasks/plugins/discovery/PluginFileCollector.java (1)

86-86: Great approach to capture the scanning directory.

This effectively ensures that each PluginFile has the directory context set before it is collected, thereby enabling better traceability.

owlplug-client/src/main/java/com/owlplug/core/utils/FileUtils.java (2)

130-140: Check for absolute vs. relative paths in getParentDirectoryName.

While this method works, consider clarifying the expected behavior for non-existent or relative paths in doc comments.


142-150: Method handles null or empty path gracefully.

Returning null for invalid input is consistent. Be mindful if any downstream code erroneously assumes a non-null name.

owlplug-client/src/main/java/com/owlplug/core/model/Plugin.java (1)

58-58: New field scanDirectoryPath fosters clarity.

Brings alignment with the changes in PluginFile, making it easy to track the plugin’s origin directory.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java (3)

42-43: Use of Spring @controller Annotation for JavaFX Controller
It’s somewhat unusual to annotate a JavaFX controller class with Spring’s @Controller. While it can work, ensure that JavaFX threads and Spring’s lifecycle are seamlessly integrated to avoid potential concurrency or bean lifecycle issues.

If you need help verifying thread-safety or ensuring that JavaFX and Spring contexts do not collide, let me know and I can generate a script to search for usage of this class in both contexts.


155-158: Batch Addition of Plugins
setPlugins(Iterable<Plugin> plugins) clears the list and iterates to add items. This is efficient for an Iterable, but keep an eye on memory usage if the dataset is large. Using pluginList.setAll(...) might be simpler, but current approach is acceptable.


173-175: Refresh Method
tableView.refresh() is straightforward; just be aware that in large tables or frequent refresh calls, it may cause performance overhead. Ensure it’s called only when necessary.

owlplug-client/src/main/java/com/owlplug/core/services/PluginService.java (2)

35-36: Imports for Set and TreeSet
Adding Set and TreeSet is appropriate for directory collections that need unique ordering. Good choice for the subsequent logic.


166-170: Method Naming Clarity
Renaming getPluginPathByFormat to getPrimaryPluginPathByFormat clarifies that it retrieves a “primary” path. This better conveys the function’s intent to the reader.

@DropSnorz DropSnorz marked this pull request as ready for review January 7, 2025 18:29
@DropSnorz
Copy link
Owner Author

@coderabbitai review

Copy link

coderabbitai bot commented Jan 7, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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: 9

🔭 Outside diff range comments (1)
owlplug-client/src/main/resources/fxml/PluginsView.fxml (1)

Add accessibility attributes to interactive elements

The following elements need accessibility improvements:

  • newLinkButton, exportButton, syncButton: Add mnemonicParsing="true" and accessibleText describing the action
  • searchTextField: Add accessibleHelp describing the search functionality
  • displayListTab, displayDirectoriesTab, displayTableTab: Add accessibleText describing each view's purpose
🔗 Analysis chain

Line range hint 17-89: Verify accessibility and keyboard navigation

The overall layout is well-structured and implements all required features. However, ensure that:

  • All interactive elements are keyboard-accessible
  • The tab order makes logical sense
  • Screen readers can properly navigate the interface

Run the following to check for missing accessibility attributes:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for missing mnemonics and accessibility properties
rg -l 'Button|TextField|Tab' owlplug-client/src/main/resources/fxml/ | xargs rg -L 'mnemonicParsing=|accessibleText=|accessibleHelp='

Length of output: 135


Script:

#!/bin/bash
# Search for Buttons with context
echo "=== Buttons ==="
rg -U "<Button.*?</Button>" --multiline owlplug-client/src/main/resources/fxml/PluginsView.fxml

echo -e "\n=== TextFields ==="
rg -U "<TextField.*?/>" --multiline owlplug-client/src/main/resources/fxml/PluginsView.fxml

echo -e "\n=== Tabs ==="
rg -U "<Tab.*?/>" --multiline owlplug-client/src/main/resources/fxml/PluginsView.fxml

Length of output: 694


Script:

#!/bin/bash
# Search with simpler patterns and context
echo "=== Buttons ==="
rg "<Button" -A 10 owlplug-client/src/main/resources/fxml/PluginsView.fxml

echo -e "\n=== TextFields ==="
rg "<TextField" -A 3 owlplug-client/src/main/resources/fxml/PluginsView.fxml

echo -e "\n=== Accessibility Properties ==="
rg -i "accessible|mnemonic|focusTraversable" owlplug-client/src/main/resources/fxml/PluginsView.fxml

Length of output: 2526

🧹 Nitpick comments (24)
owlplug-client/src/main/resources/owlplug.css (1)

93-96: LGTM! Consider enhancing table interaction styles.

The new table-view styles maintain consistency with the application's dark theme and borderless design pattern.

Consider adding hover and selected state styles for better user interaction:

 .table-view {
     -fx-background-color: card-pane-color;
     -fx-border-width: 0px;
 }
+
+.table-view .table-row-cell:hover {
+    -fx-background-color: card-pane-lightshade-color;
+}
+
+.table-view .table-row-cell:selected {
+    -fx-background-color: card-pane-darkshade-color;
+}
🧰 Tools
🪛 Biome (1.9.4)

[error] 94-94: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 95-95: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java (1)

133-145: Consider these improvements to the layout implementation.

The implementation is clean and aligns well with the new dialog management approach. Consider the following enhancements:

  1. Externalize the heading text for internationalization support
  2. Extract image dimensions to constants
  3. Add null check for the rocket image resource

Example implementation:

  protected DialogLayout getLayout() {
    DialogLayout layout = new DialogLayout();
-   Label title = new Label("Owlplug is almost ready !");
+   Label title = new Label(messages.getMessage("dialog.welcome.title"));
    title.getStyleClass().add("heading-3");
-   ImageView iv = new ImageView(this.getApplicationDefaults().rocketImage);
-   iv.setFitHeight(20);
-   iv.setFitWidth(20);
+   private static final double ICON_SIZE = 20;
+   if (this.getApplicationDefaults().rocketImage != null) {
+     ImageView iv = new ImageView(this.getApplicationDefaults().rocketImage);
+     iv.setFitHeight(ICON_SIZE);
+     iv.setFitWidth(ICON_SIZE);
+     title.setGraphic(iv);
+   }
-   title.setGraphic(iv);
    layout.setHeading(title);

    layout.setBody(lazyViewRegistry.get(LazyViewRegistry.WELCOME_VIEW));

    return layout;
  }
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/CrashRecoveryDialogController.java (3)

136-146: Fix grammatical error in heading text.

The heading text contains a grammatical error. "happens" should be "happened" in past tense.

-    Label title = new Label("Ooh, something wrong happens :(");
+    Label title = new Label("Ooh, something wrong happened :(");

143-143: Remove duplicate code for retrieving body content.

The body content retrieval is duplicated between getLayout() and getBody() methods. Consider refactoring to reuse the getBody() method.

  protected DialogLayout getLayout() {
    DialogLayout layout = new DialogLayout();
    Label title = new Label("Ooh, something wrong happened :(");
    title.getStyleClass().add("heading-3");
    layout.setHeading(title);
-    layout.setBody(lazyViewRegistry.get(LazyViewRegistry.CRASH_RECOVERY_VIEW));
+    layout.setBody(getBody());
    return layout;
  }

Also applies to: 148-150


136-146: Consider internationalizing dialog text.

The dialog text is currently hardcoded. Consider moving it to a resource bundle to support internationalization.

This would make the application more maintainable and easier to translate in the future.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/NewLinkController.java (2)

192-198: LGTM: Clean implementation of the new dialog layout pattern.

The implementation follows a consistent pattern and properly separates layout from content using lazy loading.

Consider extracting the heading text "Create a new Link" to a constants file or resource bundle for better maintainability and internationalization support:

+private static final String DIALOG_TITLE = "Create a new Link";
 protected DialogLayout getLayout() {
   DialogLayout layout = new DialogLayout();
-  Label title = new Label("Create a new Link");
+  Label title = new Label(DIALOG_TITLE);
   title.getStyleClass().add("heading-3");
   layout.setHeading(title);
   layout.setBody(lazyViewRegistry.get(LazyViewRegistry.NEW_LINK_VIEW));
   return layout;
 }

Line range hint 142-156: Consider enhancing symlink creation security and error handling.

While the current implementation includes basic validation, consider these security and UX improvements:

  1. Add path traversal protection
  2. Verify write permissions before attempting symlink creation
  3. Provide more user-friendly error messages

Here's an example enhancement for the createSymlink method:

 private boolean createSymlink(String sourcePath, String targetPath) {
   Path link = Paths.get(sourcePath);
   Path target = Paths.get(targetPath);
   try {
+    // Normalize and validate paths
+    Path normalizedLink = link.normalize();
+    Path normalizedTarget = target.normalize();
+    
+    // Check write permissions
+    if (!Files.isWritable(normalizedLink.getParent())) {
+      setErrorMessage("Cannot create link: insufficient permissions");
+      return false;
+    }
+    
     Files.createSymbolicLink(link, target);
     return true;
   } catch (IOException e) {
-    setErrorMessage("Error creating Symlink: " + e.getMessage());
+    String userMessage = "Failed to create link: " + 
+      (e.getMessage().contains("permission") ? "insufficient permissions" : 
+       "please ensure the target location exists and you have proper access");
+    setErrorMessage(userMessage);
     log.error("Error creating Symlink", e);
     return false;
   }
 }
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ExportDialogController.java (2)

79-87: Enhance file handling robustness.

While the basic file handling is correct, consider these improvements:

  1. The extension filters are set up but the code doesn't ensure the chosen file has the correct extension
  2. The error is logged but not communicated to the user

Consider this enhancement:

 if (file != null) {
+    // Ensure file has correct extension
+    String exportType = exportComboBox.getSelectionModel().getSelectedItem();
+    String path = file.getPath();
+    if ("CSV".equals(exportType) && !path.toLowerCase().endsWith(".csv")) {
+        file = new File(path + ".csv");
+    } else if ("JSON".equals(exportType) && !path.toLowerCase().endsWith(".json")) {
+        file = new File(path + ".json");
+    }
+
     try (FileWriter writer = new FileWriter(file)) {
         writer.write(exportTextArea.getText());
         writer.flush();
     } catch (IOException e) {
         log.error("Error during writing on file {}", file.getAbsolutePath(), e);
+        // Show error dialog to user
+        showErrorAlert("Export Failed", "Failed to save the file. Please try again.");
     }
 }

Line range hint 110-117: Consider using an enum for export types.

Using string literals for export types could lead to maintenance issues and typos. Consider using an enum to make the code more maintainable and type-safe.

Here's a suggested implementation:

+public enum ExportType {
+    CSV("CSV"),
+    JSON("JSON");
+    
+    private final String displayName;
+    
+    ExportType(String displayName) {
+        this.displayName = displayName;
+    }
+    
+    @Override
+    public String toString() {
+        return displayName;
+    }
+}

-private ComboBox<String> exportComboBox;
+private ComboBox<ExportType> exportComboBox;

-if ("CSV".equals(exportType)) {
+if (ExportType.CSV.equals(exportType)) {
     PluginCSVSerializer serializer = new PluginCSVSerializer();
     output.append(serializer.getHeader());
     output.append(serializer.serialize(plugins));
-} else if ("JSON".equals(exportType)) {
+} else if (ExportType.JSON.equals(exportType)) {
     PluginJsonSerializer serializer = new PluginJsonSerializer();
     output.append(serializer.serialize(plugins));
 }
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DonateDialogController.java (1)

89-89: Consider externalizing hardcoded strings for localization

The hardcoded string "Owlplug is free !" may pose challenges for internationalization and localization efforts. Externalizing this string to a resource bundle would facilitate easier translation and maintenance.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginInfoController.java (1)

104-104: Consider removing redundant null initialization.

In Java, instance fields are automatically initialized to null. The explicit initialization here is redundant.

-  private Plugin plugin = null;
+  private Plugin plugin;
owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (2)

115-131: Consider extracting common event handling logic.

The double-click handler and selection change listener logic is duplicated between tree and table views. Consider extracting this into a common method.

+  private void setupViewEventHandlers(Node view) {
+    view.setOnMouseClicked(mouseEvent -> {
+      if (mouseEvent.getClickCount() == 2) {
+        toggleInfoPaneDisplay();
+      }
+    });
+  }

   public void initialize() {
-    treeViewController.getTreeView().setOnMouseClicked(mouseEvent -> {
-      if (mouseEvent.getClickCount() == 2) {
-        toggleInfoPaneDisplay();
-      }
-    });
+    setupViewEventHandlers(treeViewController.getTreeView());

-    tableController.getTableView().setOnMouseClicked(mouseEvent -> {
-      if (mouseEvent.getClickCount() == 2) {
-        toggleInfoPaneDisplay();
-      }
-    });
+    setupViewEventHandlers(tableController.getTableView());

180-183: Add error handling for plugin sync operation.

Consider adding error handling to gracefully handle sync failures and provide user feedback.

   syncButton.setOnAction(e -> {
     this.getAnalyticsService().pageView("/app/core/action/syncPlugins");
-    pluginService.syncPlugins();
+    try {
+      pluginService.syncPlugins();
+    } catch (Exception ex) {
+      // Show error dialog or notification
+      logger.error("Failed to sync plugins", ex);
+    }
   });
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DisablePluginDialogController.java (2)

30-32: Consider making dialog dimensions configurable

Hard-coded dimensions (600x300) might not be optimal for all display sizes and DPI settings. Consider making these values configurable through application preferences or calculating them based on screen size.


39-42: Externalize dialog text to resource bundle

Consider moving the hard-coded dialog text to a resource bundle for better maintainability and internationalization support.

-    Label dialogLabel = new Label(
-            "Disabling a plugin will rename the plugin file by updating the extension. "
-                    + "The suffix \".disabled\" will be appended to the filename causing the DAW to ignore the plugin. "
-                    + "You can reactivate the plugin at any time from OwlPlug or by renaming the file manually.");
+    Label dialogLabel = new Label(resourceBundle.getString("dialog.disable.plugin.message"));
owlplug-client/src/main/java/com/owlplug/core/components/DialogManager.java (2)

66-71: Consider extracting size configuration to a separate method.

The implementation correctly sets the layout size before delegating to newDialog(layout). However, to improve maintainability and reusability, consider extracting the size configuration into a separate method.

  public Dialog newDialog(double width, double height, DialogLayout layout) {
-   layout.setMaxSize(width, height);
-   layout.setPrefSize(width, height);
+   configureLayoutSize(layout, width, height);
    return newDialog(layout);
  }

+ private void configureLayoutSize(DialogLayout layout, double width, double height) {
+   layout.setMaxSize(width, height);
+   layout.setPrefSize(width, height);
+ }

Line range hint 1-124: Good architectural improvements.

The shift from Node-based parameters to DialogLayout represents a positive architectural change that:

  1. Enforces consistent dialog layout handling
  2. Improves encapsulation of dialog components
  3. Provides a cleaner API surface

Consider documenting these changes in the migration guide to help other developers adapt to the new API.

owlplug-client/src/main/resources/fxml/PluginsView.fxml (2)

15-15: Consider using HBox.setHgrow instead of fixed-width Pane

The fixed-width Pane spacer could be replaced with a more flexible solution using HBox growth properties.

-            <!--Fixed size pane to align search box, can be replaced by a V-grow property-->
-            <Pane prefWidth="365.0" />
+            <Region HBox.hgrow="ALWAYS" />

Also applies to: 28-29


22-23: Consider extracting SVG path to a resource file

The inline SVG path makes the FXML less maintainable. Consider moving it to a separate resource file or using an icon image like the other buttons.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ListDirectoryDialogController.java (1)

102-105: Add @OverRide annotation to getLayout() method.

Since getLayout() is intended to override a method from the superclass AbstractDialogController, adding the @Override annotation enhances code clarity and helps catch potential overriding errors at compile time.

Apply this diff to add the annotation:

+  @Override
   protected DialogLayout getLayout() {
     DialogLayout layout = new DialogLayout();
     layout.setBody(lazyViewRegistry.get(LazyViewRegistry.LIST_DIRECTORY_VIEW));
     return layout;
   }
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/AbstractDialogController.java (1)

53-57: Consider extracting dialog creation logic.

The dialog creation logic looks good, but could be made more maintainable by extracting the common DialogLayout handling into a private method.

Consider applying this refactor:

   public void show() {
     onDialogShow();
+    DialogLayout layout = this.getLayout();
     if (width != -1 && height != -1) {
-      this.getDialogManager().newDialog(width, height, this.getLayout());
+      this.getDialogManager().newDialog(width, height, layout);
     } else {
-      this.getDialogManager().newDialog(this.getLayout());
+      this.getDialogManager().newDialog(layout);
     }
     this.getDialogManager().getDialog().setOverlayClose(overlayClose);
     this.getDialogManager().getDialog().show();
   }
owlplug-client/src/main/java/com/owlplug/explore/controllers/NewSourceDialogController.java (1)

163-163: Add @Override annotation to the getLayout() method

If getLayout() overrides a method from the superclass AbstractDialogController, it's best practice to use the @Override annotation to improve code clarity and catch potential errors at compile time.

Apply this diff to add the @Override annotation:

+  @Override
   protected DialogLayout getLayout() {
owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java (2)

73-93: Optimize cell value factories by avoiding unnecessary property wrapping

Currently, string values are wrapped in SimpleStringProperty for each cell, which can be inefficient. Since these values are not observable properties, you can return them directly wrapped in a ReadOnlyStringWrapper or use a lambda expression that returns the string.

Apply this diff to simplify the cell value factories:

-nameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getName()));
+nameColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getName()));

-manufacturerColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getManufacturerName()));

-versionColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getVersion()));

-categoryColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getCategory()));

97-127: Reuse TableCell implementations to reduce code duplication

The custom cell factories for directoryColumn and scanDirectoryColumn have similar implementations. Consider extracting common code into a reusable method or creating a custom TableCell subclass to reduce duplication and improve maintainability.

Example of creating a reusable method:

private TableCell<Plugin, String> createIconTableCell(ImageView icon) {
  return new TableCell<>() {
    @Override
    public void updateItem(String item, boolean empty) {
      super.updateItem(item, empty);
      if (item == null || empty) {
        setText(null);
        setGraphic(null);
      } else {
        setText(item);
        setGraphic(icon);
      }
    }
  };
}

// Then use it for both columns
directoryColumn.setCellFactory(e -> createIconTableCell(new ImageView(getApplicationDefaults().directoryImage)));
scanDirectoryColumn.setCellFactory(e -> createIconTableCell(new ImageView(getApplicationDefaults().scanDirectoryImage)));
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 174a42c and 0c2a166.

📒 Files selected for processing (18)
  • owlplug-client/src/main/java/com/owlplug/auth/controllers/AccountController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/components/ApplicationDefaults.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/components/DialogManager.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginInfoController.java (7 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/AbstractDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/CrashRecoveryDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DisablePluginDialogController.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DonateDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ExportDialogController.java (4 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ListDirectoryDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/NewLinkController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/explore/controllers/NewSourceDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java (1 hunks)
  • owlplug-client/src/main/resources/fxml/PluginsView.fxml (1 hunks)
  • owlplug-client/src/main/resources/owlplug.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • owlplug-client/src/main/java/com/owlplug/core/components/ApplicationDefaults.java
🧰 Additional context used
🪛 Biome (1.9.4)
owlplug-client/src/main/resources/owlplug.css

[error] 94-94: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 95-95: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (28)
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java (1)

21-21: LGTM! Import aligns with the new dialog layout approach.

The addition of DialogLayout import supports the architectural changes in dialog management.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/CrashRecoveryDialogController.java (2)

21-21: LGTM!

The import of DialogLayout is necessary for the new layout management implementation.


148-150: LGTM!

The getBody() method's functionality is correct, and its new position improves code organization.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/NewLinkController.java (1)

22-22: LGTM: Import addition aligns with the new dialog layout system.

The addition of the DialogLayout import supports the refactoring of dialog components into a more structured layout system.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ExportDialogController.java (2)

21-21: LGTM! Import aligns with dialog management refactoring.

The addition of DialogLayout import supports the new standardized dialog layout management system.


123-132: LGTM! Clean implementation of the new dialog layout pattern.

The new getLayout() method properly implements the standardized dialog layout management system. The code is well-structured and maintains consistent styling.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DonateDialogController.java (1)

84-94: Refactoring to getLayout() improves dialog consistency

The transition from separate getBody() and getHeading() methods to a unified getLayout() method enhances code organization and consistency across dialog controllers. The implementation correctly sets up the dialog's heading and body components using DialogLayout.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginInfoController.java (6)

26-26: LGTM: Import added for dialog controller.

The new import supports the refactored plugin disable functionality.


66-67: LGTM: Dependency injection for disable dialog controller.

Clean implementation using Spring's dependency injection.


129-133: LGTM: Well-structured disable functionality.

Clean implementation that:

  • Respects user preferences for dialog display
  • Properly delegates disable functionality to the specialized controller

137-139: LGTM: Clear and complete enable functionality.

The implementation follows a logical sequence:

  1. Enable the plugin
  2. Update the plugin info view
  3. Refresh the plugins list

Line range hint 154-196: LGTM: Excellent separation of concerns and defensive programming.

Strong implementation with:

  • Clear separation between state management and UI updates
  • Proper null checking
  • Good handling of optional values using Optional.ofNullable()
  • Comprehensive UI component updates

Line range hint 232-244: LGTM: Well-implemented uninstall functionality.

The implementation:

  • Provides clear user feedback
  • Properly handles async operations using tasks
  • Updates UI on successful completion
owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (4)

30-34: LGTM! Well-structured component organization.

The new dependencies and field declarations follow JavaFX best practices and maintain a clean MVC pattern.

Also applies to: 54-57, 64-71, 76-79


91-113: LGTM! Clean initialization of UI components.

The initialization sequence is well-structured with proper event handling setup and clear separation of concerns.


139-176: LGTM! Robust display management with persistence.

The display switching logic is well-implemented with proper state management and preference persistence.


195-211: LGTM! Clean implementation of view management methods.

The display, refresh, and selection methods are well-implemented, following the single responsibility principle and handling view-specific operations appropriately.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DisablePluginDialogController.java (1)

80-80: Verify secure file operations

Ensure that the disablePlugin operation in PluginService includes:

  1. Path traversal prevention
  2. Proper file permission checks
  3. Secure file operations that don't expose sensitive information
owlplug-client/src/main/java/com/owlplug/core/components/DialogManager.java (1)

66-71: Verify the impact of removed Node-based methods.

The shift from Node-based parameters to DialogLayout is a good architectural change. However, we should verify that all callers have been updated to use the new DialogLayout-based methods.

✅ Verification successful

All callers have been updated to use DialogLayout-based methods

The verification confirms that all usages of newDialog have been properly updated to use the new DialogLayout parameter. No instances of old Node-based method calls were found in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining calls to the old method signatures
echo "Searching for potential usage of removed methods..."

# Pattern 1: newDialog with Node body parameter
rg "newDialog\s*\(\s*[^,\)]+\s*\)" --type java

# Pattern 2: newDialog with width, height, and Node body
rg "newDialog\s*\(\s*\d+\s*,\s*\d+\s*,\s*(?!DialogLayout)[^,\)]+\s*\)" --type java

# Pattern 3: newDialog with Node body and Node heading
rg "newDialog\s*\(\s*[^,]+\s*,\s*[^,\)]+\s*\)" --type java

Length of output: 1114


Script:

#!/bin/bash
# Find the complete DialogManager class definition
echo "Searching for DialogManager class definition..."
ast-grep --pattern 'class DialogManager {
  $$$
}'

echo -e "\nSearching for potential Node-based dialog creation..."
# Simpler pattern for width, height combinations
rg "newDialog\([^)]*,[^)]*,[^)]*\)" --type java

echo -e "\nChecking for Node imports in files using DialogManager..."
rg "import.*javafx\.scene\.Node" $(rg -l "DialogManager" --type java)

Length of output: 2045

owlplug-client/src/main/resources/fxml/PluginsView.fxml (2)

53-63: Well-structured layout for multiple view types

The layout effectively supports switching between different plugin view types (List/Directories/Table) while maintaining a clean and organized structure. The non-closable tabs and left positioning provide a good user experience.


72-76: Well-implemented info pane with proper constraints

The plugin info pane implementation follows good practices:

  • Proper use of VBox.vgrow for flexible sizing
  • Correct anchoring of the included view
  • Appropriate padding for visual separation
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/ListDirectoryDialogController.java (2)

21-21: Import of DialogLayout is necessary and correctly added.

The added import statement import com.owlplug.controls.DialogLayout; is appropriate for the usage in the new getLayout() method.


102-105: Implementation of getLayout() method aligns with updated dialog management.

The getLayout() method correctly constructs and returns a DialogLayout, reflecting the application's new approach to dialog layouts. This change improves the dialog's structure and consistency across the application.

owlplug-client/src/main/java/com/owlplug/auth/controllers/AccountController.java (2)

22-22: Import statement added appropriately

The import of DialogLayout is necessary for the new getLayout() method and is correctly added.


146-149: Implementation of getLayout() method

The new getLayout() method correctly initializes a DialogLayout and sets its body using the viewRegistry. This change aligns with the updated dialog management approach and enhances the encapsulation of dialog components.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/AbstractDialogController.java (1)

21-21: LGTM! Import aligns with the new dialog layout system.

The addition of DialogLayout import supports the refactoring of dialog management system.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java (2)

210-250: Handle potential null values in createPluginContextMenu

Ensure that methods like plugin.getPath() and plugin.isDisabled() handle potential null values to prevent exceptions when the plugin data is incomplete or null.

Review the usage of plugin within createPluginContextMenu to ensure that all properties are safely accessed.


68-176: Excellent implementation of the plugin table with search functionality

The setup of the TableView, including columns, cell factories, and the binding of the search property with a FilteredList, is well-designed and follows best practices for JavaFX applications.

@DropSnorz
Copy link
Owner Author

@coderabbitai review

Copy link

coderabbitai bot commented Jan 9, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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 (7)
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/CrashRecoveryDialogController.java (2)

136-145: Fix grammatical error and consider i18n.

The implementation follows the new dialog management pattern well. However, there are two improvements needed:

  1. Fix the grammatical error in the heading: "Ooh, something wrong happens :(" should be "Ooh, something went wrong :("
  2. Consider externalizing the heading text for internationalization support.
-    Label title = new Label("Ooh, something wrong happens :(");
+    Label title = new Label(messages.getMessage("dialog.crash.heading", "Ooh, something went wrong :("));

136-145: Well-structured dialog management refactoring!

The new getLayout() implementation:

  • Improves encapsulation by combining heading and body in a single layout
  • Maintains consistency with other dialog controllers
  • Effectively uses lazy loading through LazyViewRegistry
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/NewLinkController.java (2)

190-196: Consider externalizing the dialog title for internationalization.

The implementation looks good, but consider moving the hardcoded title "Create a new Link" to a resource bundle for better internationalization support.

-    Label title = new Label("Create a new Link");
+    Label title = new Label(messageSource.getMessage("dialog.newlink.title", null, Locale.getDefault()));

190-196: Well-structured dialog management refactoring!

The consolidation of dialog layout management into a single getLayout() method improves code organization and maintains consistency with other dialog controllers in the application. The use of DialogLayout and lazy loading through LazyViewRegistry demonstrates good architectural practices.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java (1)

133-144: LGTM! Consider these maintainability improvements.

The implementation successfully consolidates the dialog layout setup into a single method. Consider these improvements:

  1. Externalize the title text to support internationalization
  2. Extract image dimensions as constants
  3. Add JavaDoc to document the method's role in the dialog lifecycle

Example implementation:

+ /** 
+  * Creates and returns the dialog layout with heading and body content.
+  * The heading includes the welcome message and rocket icon, while the body
+  * is lazily loaded from the welcome view.
+  * @return DialogLayout instance configured with heading and body
+  */
  protected DialogLayout getLayout() {
-   Label title = new Label("Owlplug is almost ready !");
+   private static final double ICON_SIZE = 20;
+   Label title = new Label(messages.getString("dialog.welcome.title"));
    title.getStyleClass().add("heading-3");
    ImageView iv = new ImageView(this.getApplicationDefaults().rocketImage);
-   iv.setFitHeight(20);
-   iv.setFitWidth(20);
+   iv.setFitHeight(ICON_SIZE);
+   iv.setFitWidth(ICON_SIZE);
    title.setGraphic(iv);

    DialogLayout layout = new DialogLayout();
    layout.setHeading(title);
    layout.setBody(lazyViewRegistry.get(LazyViewRegistry.WELCOME_VIEW));

    return layout;
  }
owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (2)

91-94: Consider grouping initialization logic into separate methods

While the initialization logic is correct, consider extracting the UI setup into separate private methods for better organization and readability:

 @FXML
 public void initialize() {
+    initializeButtons();
+    initializeDisplayComponents();
+    initializeTreeView();
+    initializeTableView();
+    setDefaultDisplayState();
 }

+private void initializeDisplayComponents() {
+    pluginsContainer.getChildren().add(treeViewController.getTreeView());
+    pluginsContainer.getChildren().add(tableController.getTableView());
+    displaySwitchTabPane.getStyleClass().add(JMetroStyleClass.UNDERLINE_TAB_PANE);
+}

+private void setDefaultDisplayState() {
+    treeViewController.setDisplayMode(PluginTreeViewController.Display.FlatTree);
+    treeViewController.getTreeView().setVisible(true);
+    treeViewController.getTreeView().setManaged(true);
+    tableController.getTableView().setManaged(false);
+    tableController.getTableView().setVisible(false);
+    setInfoPaneDisplay(true);
+}

Also applies to: 141-149


152-170: Consider handling preference storage asynchronously

The preference storage in the tab selection handler might cause UI lag on slower systems.

-this.getPreferences().put(ApplicationDefaults.PLUGIN_PREFERRED_DISPLAY_KEY, "LIST");
+CompletableFuture.runAsync(() -> 
+    this.getPreferences().put(ApplicationDefaults.PLUGIN_PREFERRED_DISPLAY_KEY, "LIST"));
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0c2a166 and 0fea25d.

📒 Files selected for processing (9)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTreeViewController.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/CrashRecoveryDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DisablePluginDialogController.java (1 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/NewLinkController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java (2 hunks)
  • owlplug-client/src/main/java/com/owlplug/core/services/PluginService.java (3 hunks)
  • owlplug-client/src/main/java/com/owlplug/explore/controllers/NewSourceDialogController.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • owlplug-client/src/main/java/com/owlplug/core/services/PluginService.java
  • owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/DisablePluginDialogController.java
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTableController.java
  • owlplug-client/src/main/java/com/owlplug/core/controllers/PluginTreeViewController.java
🧰 Additional context used
📓 Learnings (1)
owlplug-client/src/main/java/com/owlplug/explore/controllers/NewSourceDialogController.java (1)
Learnt from: DropSnorz
PR: DropSnorz/OwlPlug#280
File: owlplug-client/src/main/java/com/owlplug/explore/controllers/NewSourceDialogController.java:167-169
Timestamp: 2025-01-09T18:06:36.822Z
Learning: The `serverImage` in `ApplicationDefaults` is guaranteed to be non-null, so null checks are not required when using it to create an `ImageView`.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (10)
owlplug-client/src/main/java/com/owlplug/explore/controllers/NewSourceDialogController.java (2)

21-21: LGTM!

The import statement for DialogLayout is correctly added to support the new layout management approach.


162-175: Well-structured layout management implementation!

The new getLayout() method effectively combines heading and body into a single DialogLayout, improving the organization and maintainability of the dialog's UI structure. The implementation:

  • Creates a properly styled heading with an appropriate icon
  • Maintains lazy loading of the body content
  • Follows a consistent pattern seen across other dialog controllers
owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/CrashRecoveryDialogController.java (1)

21-21: LGTM!

The addition of the DialogLayout import aligns with the new dialog management approach.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/NewLinkController.java (1)

22-22: LGTM!

The DialogLayout import is appropriately placed and aligns with the dialog management refactoring.

owlplug-client/src/main/java/com/owlplug/core/controllers/dialogs/WelcomeDialogController.java (1)

21-21: LGTM!

The addition of the DialogLayout import aligns with the new dialog layout management approach.

owlplug-client/src/main/java/com/owlplug/core/controllers/PluginsController.java (5)

30-35: LGTM: Well-structured field declarations and dependencies

The new field declarations and dependencies are properly organized, following consistent naming conventions and Spring's dependency injection patterns.

Also applies to: 54-57, 64-71, 76-79


100-114: LGTM: Well-implemented event handlers and bindings

The event handlers and bindings for both tree view and table view are properly implemented with consistent behavior.

Also applies to: 121-134


216-223: LGTM: Clean implementation of info pane visibility management

The info pane visibility methods are concise and properly manage both the visibility and layout properties.


197-200: Consider adding null check for plugins

The displayPlugins method should handle the case where pluginDAO.findAll() returns null.

 public void displayPlugins() {
     Iterable<Plugin> plugins = pluginDAO.findAll();
+    if (plugins == null) {
+        plugins = Collections.emptyList();
+    }
     treeViewController.setPlugins(plugins);
     tableController.setPlugins(plugins);
 }

203-209: Add null check for tab selection

The selectPluginById method should verify that the tab selection is not null.

 public void selectPluginById(long id) {
+    if (displaySwitchTabPane.getSelectionModel().getSelectedItem() == null) {
+        return;
+    }
     if (displaySwitchTabPane.getSelectionModel().getSelectedItem().equals(displayTableTab)) {
         tableController.selectPluginById(id);
     } else {
         treeViewController.selectPluginById(id);
     }
 }

@DropSnorz DropSnorz merged commit 5f3c27b into dev Jan 9, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant