@@ -44,6 +44,8 @@ function createDemoData(arrSize: number, useHomepage?: boolean) {
4444 description : `This is a plugin for this project PLUGIN A${ i } ` ,
4545 isEnabled : i % 2 === 0 ,
4646 isCompatible : i % 2 === 0 ,
47+ type : 'shipped' ,
48+ isLoaded : true ,
4749 } ;
4850
4951 if ( useHomepage ) {
@@ -57,6 +59,127 @@ function createDemoData(arrSize: number, useHomepage?: boolean) {
5759 return pluginArr ;
5860}
5961
62+ /**
63+ * createPluginsWithMultipleLocations creates example data showing the same plugin
64+ * installed in different locations (development, user, shipped) with proper priority handling.
65+ */
66+ function createPluginsWithMultipleLocations ( ) : PluginInfo [ ] {
67+ return [
68+ // Plugin installed in all three locations - development version loads
69+ {
70+ name : 'awesome-plugin' ,
71+ description : 'An awesome plugin installed in development folder' ,
72+ type : 'development' as const ,
73+ isEnabled : true ,
74+ isCompatible : true ,
75+ isLoaded : true ,
76+ homepage : 'https://example.com/awesome-plugin' ,
77+ } ,
78+ {
79+ name : 'awesome-plugin' ,
80+ description : 'An awesome plugin installed in user folder' ,
81+ type : 'user' as const ,
82+ isEnabled : true ,
83+ isCompatible : true ,
84+ isLoaded : false ,
85+ overriddenBy : 'development' as const ,
86+ homepage : 'https://example.com/awesome-plugin' ,
87+ } ,
88+ {
89+ name : 'awesome-plugin' ,
90+ description : 'An awesome plugin shipped with Headlamp' ,
91+ type : 'shipped' as const ,
92+ isEnabled : true ,
93+ isCompatible : true ,
94+ isLoaded : false ,
95+ overriddenBy : 'development' as const ,
96+ homepage : 'https://example.com/awesome-plugin' ,
97+ } ,
98+ // Plugin in user and shipped - user version loads
99+ {
100+ name : 'monitoring-plugin' ,
101+ description : 'Monitoring plugin installed by user' ,
102+ type : 'user' as const ,
103+ isEnabled : true ,
104+ isCompatible : true ,
105+ isLoaded : true ,
106+ homepage : 'https://example.com/monitoring-plugin' ,
107+ repository : { url : 'https://github.com/example/monitoring-plugin' } ,
108+ } ,
109+ {
110+ name : 'monitoring-plugin' ,
111+ description : 'Monitoring plugin shipped with Headlamp' ,
112+ type : 'shipped' as const ,
113+ isEnabled : true ,
114+ isCompatible : true ,
115+ isLoaded : false ,
116+ overriddenBy : 'user' as const ,
117+ homepage : 'https://example.com/monitoring-plugin' ,
118+ repository : { url : 'https://github.com/example/monitoring-plugin' } ,
119+ } ,
120+ // Plugin only in development
121+ {
122+ name : 'dev-only-plugin' ,
123+ description : 'A plugin only in development folder' ,
124+ type : 'development' as const ,
125+ isEnabled : true ,
126+ isCompatible : true ,
127+ isLoaded : true ,
128+ homepage : 'https://example.com/dev-only' ,
129+ } ,
130+ // Plugin only in user folder
131+ {
132+ name : 'custom-plugin' ,
133+ description : 'A custom plugin installed by user' ,
134+ type : 'user' as const ,
135+ isEnabled : true ,
136+ isCompatible : true ,
137+ isLoaded : true ,
138+ homepage : 'https://example.com/custom-plugin' ,
139+ repository : { url : 'https://github.com/example/custom-plugin' } ,
140+ } ,
141+ // Plugin only shipped
142+ {
143+ name : 'default-plugin' ,
144+ description : 'A default plugin shipped with Headlamp' ,
145+ type : 'shipped' as const ,
146+ isEnabled : true ,
147+ isCompatible : true ,
148+ isLoaded : true ,
149+ homepage : 'https://headlamp.dev/plugins/default' ,
150+ } ,
151+ // Disabled development plugin - user version loads instead
152+ {
153+ name : 'flexible-plugin' ,
154+ description : 'Flexible plugin in development (disabled)' ,
155+ type : 'development' as const ,
156+ isEnabled : false ,
157+ isCompatible : true ,
158+ isLoaded : false ,
159+ homepage : 'https://example.com/flexible-plugin' ,
160+ } ,
161+ {
162+ name : 'flexible-plugin' ,
163+ description : 'Flexible plugin installed by user' ,
164+ type : 'user' as const ,
165+ isEnabled : true ,
166+ isCompatible : true ,
167+ isLoaded : true ,
168+ homepage : 'https://example.com/flexible-plugin' ,
169+ } ,
170+ {
171+ name : 'flexible-plugin' ,
172+ description : 'Flexible plugin shipped with Headlamp' ,
173+ type : 'shipped' as const ,
174+ isEnabled : true ,
175+ isCompatible : true ,
176+ isLoaded : false ,
177+ overriddenBy : 'user' as const ,
178+ homepage : 'https://example.com/flexible-plugin' ,
179+ } ,
180+ ] ;
181+ }
182+
60183/**
61184 * Creation of data arrays ranging from 0 to 50 to demo state of empty, few, many, and large numbers of data objects.
62185 * NOTE: The numbers used are up to the users preference.
@@ -115,3 +238,77 @@ EmptyHomepageItems.args = {
115238 console . log ( 'Empty Homepage' , plugins ) ;
116239 } ,
117240} ;
241+
242+ /**
243+ * createMigrationScenario creates example data showing the migration behavior
244+ * where catalog-installed plugins in the old plugins directory are treated as "user" plugins.
245+ *
246+ * The backend detects catalog-installed plugins by checking for isManagedByHeadlampPlugin=true
247+ * in the plugin's package.json. These plugins are automatically reclassified from "development"
248+ * to "user" type, ensuring correct priority order (development > user > shipped).
249+ */
250+ function createMigrationScenario ( ) : PluginInfo [ ] {
251+ return [
252+ // Catalog-installed plugin in old location (plugins dir) - treated as "user" type
253+ // This simulates a plugin that was installed via the catalog before the user-plugins directory existed.
254+ // Backend checks package.json for isManagedByHeadlampPlugin=true and reclassifies it as "user" type.
255+ {
256+ name : 'prometheus' ,
257+ description :
258+ 'Prometheus monitoring plugin (catalog-installed in old location, has isManagedByHeadlampPlugin=true)' ,
259+ type : 'user' as const , // Backend detects isManagedByHeadlampPlugin=true and treats as user
260+ isEnabled : true ,
261+ isCompatible : true ,
262+ isLoaded : true ,
263+ homepage : 'https://artifacthub.io/packages/headlamp/headlamp/prometheus' ,
264+ } ,
265+ // New catalog-installed plugin in correct location (user-plugins)
266+ {
267+ name : 'flux' ,
268+ description : 'Flux GitOps plugin (catalog-installed in new location)' ,
269+ type : 'user' as const ,
270+ isEnabled : true ,
271+ isCompatible : true ,
272+ isLoaded : true ,
273+ homepage : 'https://artifacthub.io/packages/headlamp/headlamp/flux' ,
274+ } ,
275+ // True development plugin - gets higher priority
276+ {
277+ name : 'my-dev-plugin' ,
278+ description : 'A plugin being actively developed' ,
279+ type : 'development' as const ,
280+ isEnabled : true ,
281+ isCompatible : true ,
282+ isLoaded : true ,
283+ homepage : 'https://example.com/my-dev-plugin' ,
284+ } ,
285+ // Shipped plugin
286+ {
287+ name : 'default-dashboard' ,
288+ description : 'Default dashboard plugin' ,
289+ type : 'shipped' as const ,
290+ isEnabled : true ,
291+ isCompatible : true ,
292+ isLoaded : true ,
293+ homepage : 'https://headlamp.dev/plugins/dashboard' ,
294+ } ,
295+ ] ;
296+ }
297+
298+ /** Story showing plugins installed in multiple locations with priority handling */
299+ export const MultipleLocations = Template . bind ( { } ) ;
300+ MultipleLocations . args = {
301+ plugins : createPluginsWithMultipleLocations ( ) ,
302+ onSave : ( plugins : any ) => {
303+ console . log ( 'Multiple Locations' , plugins ) ;
304+ } ,
305+ } ;
306+
307+ /** Story demonstrating migration of catalog-installed plugins from old location */
308+ export const MigrationScenario = Template . bind ( { } ) ;
309+ MigrationScenario . args = {
310+ plugins : createMigrationScenario ( ) ,
311+ onSave : ( plugins : any ) => {
312+ console . log ( 'Migration Scenario' , plugins ) ;
313+ } ,
314+ } ;
0 commit comments