Skip to content

Commit f10ee45

Browse files
committed
frontend/PluginSettings: Add stories for the multi type plugins
1 parent c0cc606 commit f10ee45

File tree

4 files changed

+1945
-1
lines changed

4 files changed

+1945
-1
lines changed

e2e-tests/tests/headlamp.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ test('GET /plugins/list returns plugins list', async ({ page }) => {
3838

3939
const json = await response.json();
4040
expect(json.length).toBeGreaterThan(0);
41-
expect(json.some(str => str.includes('plugins/'))).toBeTruthy();
41+
expect(json.some(plugin => plugin.path && plugin.path.includes('plugins/'))).toBeTruthy();
4242
});
4343
// --- Plugin tests end --- //
4444

frontend/src/components/App/PluginSettings/PluginSettings.stories.tsx

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)