-
Notifications
You must be signed in to change notification settings - Fork 458
plugins: Add concept of "shipped", "user-installed", and "dev" plugin types #4095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
plugins: Add concept of "shipped", "user-installed", and "dev" plugin types #4095
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a plugin loading system that differentiates plugins by type (shipped/user-installed/development) and loads them according to a priority-based system. Development plugins have the highest priority, followed by user-installed, then shipped plugins. When multiple versions of the same plugin exist, only the highest priority enabled version is loaded.
Key Changes:
- Backend now returns plugin metadata including type (development/user/shipped) alongside path
- Frontend applies priority-based loading logic, marking which plugin versions are loaded vs overridden
- New
user-pluginsdirectory introduced to separate user-installed plugins from development plugins - UI updated to display plugin type, status (Loaded/Not Loaded/Disabled), and override information
Reviewed Changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
plugins/pluginctl/src/plugin-management.js |
Updated default plugins directory from 'plugins' to 'user-plugins' |
frontend/src/plugin/pluginsSlice.ts |
Added type, isLoaded, and overriddenBy fields to PluginInfo type |
frontend/src/plugin/index.ts |
Implemented applyPluginPriority function and updated plugin loading logic |
frontend/src/components/App/PluginSettings/PluginSettings.tsx |
Added Type column and updated Status column to show override information |
frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx |
Added type chip display to plugin details header |
backend/pkg/plugins/plugins.go |
Implemented PluginMetadata struct and updated functions to handle three plugin directories |
backend/pkg/config/config.go |
Added UserPluginsDir configuration and defaultUserPluginDir function |
backend/cmd/server.go |
Updated to pass UserPluginDir to configuration |
app/electron/plugin-management.ts |
Added defaultUserPluginsDir function and updated install/update methods |
| Multiple snapshot files | Updated test snapshots to reflect new Type column and Status display changes |
Comments suppressed due to low confidence (1)
frontend/src/plugin/index.ts:1
- The comment on line 286 states plugins with the same name are treated as separate entries, but the actual implementation in applyPluginPriority groups them by name and applies priority logic. This comment is misleading about the actual behavior.
/*
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@joaquimrocha seems there's some issues with CI checks?
Can you please add some tests for some of the changes?
What happens to plugins people already have installed in the old plugins directory? Will plugins installed to the old folder be ignored by this new code?
I guess they will still be interpreted as dev plugins. Hmm, this actually can be a problem if we installed the plugins in the old fashion into plugins/ and now they are assumed to be dev plugins which will take over priority over any updates. Let me quickly see if I can have a migration path. |
I have new stories in the last commit. |
3336ce8 to
f10ee45
Compare
|
One of the checks is failing. Some of the commit subject lines need the context part added. |
a8ec734 to
7fad445
Compare
7fad445 to
87803ab
Compare
f4628a9 to
e9bf6ad
Compare
|
updated the failing snapshots and rebased against main again |
|
Maybe not for this PR, but this issue would be a good improvement:
|
I can add an "open folder" button to each plugin but in its details view. WDYT? |
e9bf6ad to
b18d540
Compare
Also noticed that "Reload" button not working here may be due to the use of the |
b18d540 to
b750fb1
Compare
b750fb1 to
2b0c30b
Compare
2b0c30b to
42c3ba6
Compare
42c3ba6 to
f52c88f
Compare
|
@joaquimrocha
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good.
Some issues in CI though...
- rebase to fix this conflict in app/electron/preload.ts
make backend-lintmake frontend-test- snapshots need an update
src/components/App/PluginSettings/PluginSettingsDetails.tsx:17:10 - error TS2300: Duplicate identifier 'Typography'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 38 out of 38 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { Typography } from '@mui/material'; | ||
| import Box, { BoxProps } from '@mui/material/Box'; | ||
| import Button from '@mui/material/Button'; | ||
| import Chip from '@mui/material/Chip'; | ||
| import Stack from '@mui/material/Stack'; | ||
| import Typography from '@mui/material/Typography'; |
Copilot
AI
Nov 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typography is imported twice - once from '@mui/material' on line 17 and again on line 22. Remove the duplicate import on line 17.
| if !os.IsNotExist(err) { | ||
| logger.Log(logger.LevelInfo, map[string]string{"pluginPath": pluginPath}, | ||
| err, "Not including plugin path, error checking main.js") | ||
| } |
Copilot
AI
Nov 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says 'Only log if it's not a "does not exist" error (which is expected during deletion)' but this logging is at LevelInfo. During deletion, there may be race conditions where the directory is being removed. Consider using a more specific log level or adding context about whether this is during a deletion operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, This would be nice to have, but we can skip it for now.
| if (newEnabledState && p.name === plugName && p.type !== plugType) { | ||
| return { ...p, isEnabled: false }; | ||
| } |
Copilot
AI
Nov 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When enabling one version of a plugin, this automatically disables all other versions with the same name. This behavior should be documented in the function's JSDoc comment as it's a significant side effect that affects user data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, This would be nice to have, but we can skip it for now.
| func Delete(userPluginDir, pluginDir, filename, pluginType string) error { | ||
| // Validate plugin type if provided | ||
| if pluginType != "" && pluginType != "user" && pluginType != "development" { | ||
| return fmt.Errorf("invalid plugin type '%s': must be 'user' or 'development'", pluginType) |
Copilot
AI
Nov 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'shipped' plugin type exists in the system but is not allowed for deletion. The error message should clarify that shipped plugins cannot be deleted, rather than implying 'shipped' is invalid. Consider: "invalid plugin type '%s': must be 'user' or 'development' (shipped plugins cannot be deleted)"
| return fmt.Errorf("invalid plugin type '%s': must be 'user' or 'development'", pluginType) | |
| return fmt.Errorf("invalid plugin type '%s': must be 'user' or 'development' (shipped plugins cannot be deleted)", pluginType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, This message improvement would be nice-to-have, we could skip it for now.
f52c88f to
2eff944
Compare
This will be used for the catalog-installed plugins, so we end up with static, user, and dev plugins. Static are plugins shipped in Headlamp. User are plugins installed by the user (via the catalog). Dev are plugins used during development, like when we are adding a new feature to a plugin.
Type being shipped/user/dev.
Allow specifying plugin type ('user' or 'development') when deleting
plugins. This prevents accidentally deleting the wrong plugin when
plugins with the same name exist in both directories.
When type is specified, only that directory is checked. When omitted,
maintains backward compatibility by checking both directories in
priority order (user-plugins first, then development).
Now that we have introduced user-installed plugins as a different location.
Otherwise, when there are many plugins in the page, the button is pushed down and can appear as if there is no Save button.
To be consistent with other designs we have.
From the PluginSettingsDetails.
2eff944 to
2e5b032
Compare


Summary
Define plugins as being of different types (shipped/user-installed/dev) and load them according to the description set in #3628 .
Related Issue
Fixes #3628 .
Steps to Test
(use the app)
npm startrun inside a plugin print the correct folder where the plugin is copied to?Screenshots (if applicable)