- Calculate total installed plugins count
- Calculate total active/enabled plugins count
- Display statistics in page header with icons
- Shows 'Installed: X' and 'Active: Y' counts
- Statistics only shown when plugins are installed
- Improves visibility of plugin status at a glance
- Fix except block indentation to match try block
- Add error handling for enrichment in stale cache fallback
- Ensures proper exception handling structure
- Wrap mailUtilities.checkHome in try-except
- Add try-except around _enrich_store_plugins calls
- If enrichment fails, return plugins without enrichment instead of 500 error
- Add error handling for _is_plugin_enabled calls
- Prevents HTTP 500 errors when plugin store loading fails
- Fixes issue where installing discordWebhooks caused plugin store to fail
- Remove redundant local import of pluginInstaller inside install_from_store function
- pluginInstaller is already imported at module level (line 20)
- The local import was creating a variable shadowing issue
- When the cleanup code path wasn't executed, pluginInstaller was referenced before assignment
- Fixes installation from store failing with variable reference error
- Only check /usr/local/CyberCP/ for installed status, not /home/cyberpanel/plugins/
- Require both plugin directory AND meta.xml to exist for installed status
- Plugins in source directory are not considered installed
- Fixes issue where Discord Webhooks, Fail2ban, Premium Plugin Example, and Test Plugin showed as installed when they weren't
Previously, the check used: os.path.exists(installed_path) or os.path.exists(source_path)
This incorrectly marked plugins as installed if they existed in the source directory.
Now uses: os.path.exists(installed_path) and os.path.exists(installed_meta)
This correctly only marks plugins as installed if they're actually in /usr/local/CyberCP/ with meta.xml
- Make toggleView more flexible - only require the specific view element needed
- Store view can now work even when gridView/tableView don't exist (no plugins installed)
- Fix initialization to directly show store view without calling toggleView recursively
- Find store button by text content instead of array index for reliability
- Prevents 'View elements not found' errors when loading Plugin Store with no installed plugins
- Hide Grid and Table view buttons when plugins list is empty
- Only show Plugin Store button when no plugins are installed
- Improves UX by preventing clicks on non-functional buttons
- Combined with null checks, ensures no JavaScript errors occur
- Add null checks for gridView, tableView, and storeView elements
- Prevent 'Cannot read properties of null' errors when elements don't exist
- Add null checks for viewBtns array access
- Add function existence checks before calling setupStoreSearch, loadPluginStore, displayStorePlugins
- Improve initialization code with better error handling
- Fixes Plugin Store loading errors when no plugins are installed
- Filter pluginList to only include plugins where installed == True
- Uninstalled plugins will only appear in Plugin Store, not Installed Plugins
- This fixes the issue where uninstalled plugins were still showing locally
- Plugins in /home/cyberpanel/plugins/ but not in /usr/local/CyberCP/ are now hidden from Installed Plugins
- Verify plugin directory is actually removed after removeFiles()
- If directory still exists, retry with ProcessUtilities.normalExecutioner()
- Return error if directory still exists after all attempts
- Prevents silent failures where uninstall appears successful but plugin remains
Fixes: Plugins showing as installed after 'successful' uninstall
- Comment out emailMarketing menu item in baseTemplate/index.html
- Skip emailMarketing in pluginHolder/views.py when listing plugins
- Prevents HTTP 500 error when template tries to reverse 'emailMarketing' URL
Fixes: HTTP 500 on /plugins/installed after emailMarketing removal
- Use pluginInstaller.removeFiles() which handles permissions properly
- Add fallback to rm -rf if pluginInstaller method fails
- Better error handling and logging
- Applied to both install_plugin and install_from_store functions
Fixes: Incomplete plugin directory cleanup failures due to permission issues
- Added NEW badge for plugins updated within last 3 months (90 days)
- Added Stale badge for plugins not updated in last 2 years (730 days)
- Removed Author, Status, and Active columns from Plugin Store view
- Fixed intermittent old table display with cache-busting v7
- Added column count validation to ensure correct 8-column structure
- Added tooltips for NEW and Stale badges with descriptive messages
- Cleared plugin store cache to prevent stale data display
- Updated cache-busting version to v7 to force browser refresh
- Added code to detect and remove any duplicate view-toggle divs
- Keeps only the one with id='plugins-view-toggle'
- This handles cases where browser cache or template cache shows duplicates
- Added id='plugins-view-toggle' to view-toggle div to prevent duplicates
- Updated toggleView() to only select buttons from the main view-toggle
- This should prevent any duplicate button issues
- Moved view toggle (Grid View, Table View, Plugin Store, Plugin Development Guide) to top of plugins section
- Removed duplicate view toggle that appeared at bottom
- Now only one set of view toggle buttons appears at the top
- Removed duplicate view toggle section that appeared when plugins exist
- Kept single view toggle that's always visible (after plugins section)
- Fixes issue where Grid View, Table View, Plugin Store buttons appeared twice
- Added author display to Grid View plugin cards
- Added Author column to Table View
- Added Author column to Plugin Store table view
- Author information is extracted from plugin meta.xml files
- Displays 'Unknown' if author is not specified in meta.xml
- Update examplePlugin and emailMarketing meta.xml to use 1.0.0 format
- Add comprehensive semantic versioning section to plugin help page
- Explain major/minor/patch version numbers with examples
- Standardize all plugins to use three-number version format (X.Y.Z)
- Improve version tracking and update clarity for plugin developers
- Change default manage_url from /plugins/{plugin}/settings/ to /plugins/{plugin}/
- Many plugins don't have a /settings/ route but have a main route
- Ensures Settings button works for plugins like examplePlugin that only have a main route
- Still respects settings_url and url from meta.xml if provided
- Add fallback handling for emailMarketing in else branch
- Ensures Settings button always has correct URL (/emailMarketing/)
- Prevents any edge case where manage_url might be wrong
- Add author field extraction from meta.xml in both plugin processing loops
- Update discordWebhooks meta.xml to include author: Master3395
- Update examplePlugin meta.xml to include author: usmannasir
- Add Plugin Settings button next to Deactivate/Uninstall buttons in both grid and table views
- Special handling for emailMarketing core plugin URL (/emailMarketing/ instead of /plugins/emailMarketing/)
- Add btn-settings styling for Settings button with hover effects
- Convert linked images (badges): [](link_url) to clickable <a><img></a>
- Convert regular images:  to <img> tags
- Convert regular links: [text](url) to <a> tags
- All external links open in new tab with security attributes
- Preserve existing HTML tags when wrapping paragraphs
- Fixes badge links not working in README.md content
- Fetch CHANGELOG.md from GitHub if not found locally (non-blocking, 3s timeout)
- Fetch README.md from GitHub if no local help files found
- Provides version history and documentation for plugins from GitHub
- All GitHub fetches are optional and fail silently to avoid slow page loads
- Enhances plugin-specific help pages with complete information
- Update examplePlugin version from 0 to 1.0 in meta.xml
- Implement proper plugin_help view to show plugin-specific information
- Reads plugin meta.xml for name, version, author, description
- Looks for README.md, HELP.md, CHANGELOG.md files in plugin directory
- Displays plugin information and version history
- Now shows plugin-specific help instead of redirecting to development guide
- Individual plugin Help buttons now show plugin-specific information
- Add specific CSS rules for a.view-btn to ensure proper styling
- Help button now displays correctly next to Plugin Store button
- Matches styling of other view toggle buttons (hover effects, colors)
- Button is clearly visible and accessible for users
- Add help button next to CyberPanel Plugin Store button
- Links to /plugins/help/ (Plugin Development Guide)
- Helps users understand how to work with plugins
- Button appears in both view toggle sections (with and without plugins)
- Styled consistently with other view toggle buttons
- Wrap second Django template code example (line 500) with {% verbatim %} tags
- Ensures all Django template syntax in code examples is properly escaped
- Fixes remaining 'Invalid block tag' error on line 660
- Replace {% with {%% in code examples to prevent template parsing errors
- Fixes 'block tag with name title appears more than once' error
- Code examples now display correctly without being parsed as actual template blocks
- Move processed_plugins.add() to after plugin is successfully added to pluginList
- Prevents plugins from being marked as processed if they fail validation
- Ensures pm2Manager and other store-installed plugins show up correctly
- Add logic to check installed plugins that don't have source directories
- Fixes issue where PM2 Manager (installed from store) wasn't showing
- Moved processed_plugins.add() to correct location in code flow
- Now shows all 4 installed plugins: testPlugin, discordWebhooks, fail2ban, pm2Manager
- Add logic to check installed plugins that don't have source directories
- Fixes issue where PM2 Manager (installed from store) wasn't showing in installed list
- Now shows all installed plugins regardless of whether they have source in /home/cyberpanel/plugins/
- Prevents duplicate plugin entries by tracking processed plugins
- Add UTF-8 encoding to all file operations in pluginInstaller
- Fix ASCII codec error in removeFromSettings and removeFromURLs
- Add 2 second delay after installation to allow filesystem sync
- Fix fileinput.input encoding issue in removeFromURLs
- Update uninstall confirmation message to warn about data deletion
- Fixes plugin installation and uninstallation from store
- Revert GitHub API fetching in installed() view to use local file modification time (prevents timeouts)
- Fix fileinput.input() encoding issue in pluginInstaller.removeFromURLs()
- Replace fileinput with manual file read/write using utf-8 encoding
- Add missing import re to pluginInstaller
- Fixes 500 Internal Server Error on CyberPanel pages
- Fixes plugin installation from store
- Use local file modification time by default to prevent timeouts
- GitHub API calls commented out (can be enabled if needed)
- Improves page load performance
- Prevents 500 errors from API timeouts
- Add plugin name as directory prefix in ZIP file
- pluginInstaller expects ZIP to contain plugin_name/ directory
- Fixes installation failure where plugin directory was not created