Skip to content

Commit 0471f37

Browse files
committed
Handle UI plugins with chart version and appVersion not matching
This change adds handling for UIPlugins which are installed from charts where chart version and chart appVersion don't match. - Determine plugin upgradability by comparing UIPlugin version with chart appVersion with a fallback to chart version if appVersion is not available - Update PluginInfoPanel to handle plugin version not matching chart version by checking appVersion first - Update InstallDialog to handle plugin version not matching chart version by checking appVersion first - Display plugin versions in `appVersion (chart version)` format if appVersion differs from chart version Fixes issue #14204
1 parent 3806ccf commit 0471f37

File tree

5 files changed

+147
-33
lines changed

5 files changed

+147
-33
lines changed

shell/dialog/InstallExtensionDialog.vue

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations
66
import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
77
import Banner from '@components/Banner/Banner.vue';
88
import { SETTING } from '@shell/config/settings';
9+
import { getPluginChartVersion, getPluginChartVersionLabel } from '@shell/utils/uiplugins';
910
1011
// Note: This dialog handles installation and update of a plugin
1112
@@ -62,21 +63,23 @@ export default {
6263
},
6364
6465
async fetch() {
66+
const chartVersion = getPluginChartVersion(this.plugin);
67+
6568
// Default to latest version on install (this is default on the plugin)
66-
this.version = this.plugin?.displayVersion;
69+
this.version = chartVersion;
6770
6871
if (this.mode === 'update') {
69-
this.currentVersion = this.plugin?.displayVersion;
72+
this.currentVersion = chartVersion;
7073
7174
// Update to latest version, so take the first version
7275
if (this.plugin?.installableVersions?.length > 0) {
7376
this.version = this.plugin?.installableVersions?.[0]?.version;
7477
}
7578
} else if (this.mode === 'rollback') {
7679
// Find the newest version once we remove the current version
77-
const versionNames = this.plugin?.installableVersions.filter((v) => v.version !== this.plugin?.displayVersion);
80+
const versionNames = this.plugin.installableVersions.filter((v) => v.version !== chartVersion);
7881
79-
this.currentVersion = this.plugin?.displayVersion;
82+
this.currentVersion = chartVersion;
8083
8184
if (versionNames.length > 0) {
8285
this.version = versionNames[0].version;
@@ -131,7 +134,7 @@ export default {
131134
132135
return versions.map((version) => {
133136
return {
134-
label: version.version,
137+
label: getPluginChartVersionLabel(version),
135138
value: version.version,
136139
};
137140
});

shell/pages/c/_cluster/uiplugins/PluginInfoPanel.vue

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import LazyImage from '@shell/components/LazyImage';
66
import { MANAGEMENT } from '@shell/config/types';
77
import { SETTING } from '@shell/config/settings';
88
import { useWatcherBasedSetupFocusTrapWithDestroyIncluded } from '@shell/composables/focusTrap';
9+
import { getPluginChartVersionLabel, getPluginChartVersion } from '@shell/utils/uiplugins';
910
1011
export default {
1112
async fetch() {
@@ -79,9 +80,11 @@ export default {
7980
},
8081
8182
async loadPluginVersionInfo(version) {
82-
const versionName = version || this.info.displayVersion;
83+
const pluginChartVersion = getPluginChartVersion(this.info);
8384
84-
const isVersionNotCompatible = this.info.versions?.find((v) => v.version === versionName && !v.isVersionCompatible);
85+
const versionName = version || pluginChartVersion || this.info.versions?.[0]?.version;
86+
87+
const isVersionNotCompatible = this.info.versions?.find((v) => versionName === (v.appVersion ?? v.version) && !v.isVersionCompatible);
8588
8689
if (!this.info.chart || isVersionNotCompatible) {
8790
return;
@@ -147,6 +150,10 @@ export default {
147150
if (event.key === 'Escape') {
148151
this.hide();
149152
}
153+
},
154+
155+
getVersionLabel(version) {
156+
return getPluginChartVersionLabel(version);
150157
}
151158
}
152159
};
@@ -264,7 +271,7 @@ export default {
264271
@click="loadPluginVersionInfo(v.version)"
265272
@keyup.enter.space="loadPluginVersionInfo(v.version)"
266273
>
267-
{{ v.version }}
274+
{{ getVersionLabel(v) }}
268275
</a>
269276
</div>
270277
</div>

shell/pages/c/_cluster/uiplugins/index.vue

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
} from '@shell/config/uiplugins';
3333
import TabTitle from '@shell/components/TabTitle';
3434
import versions from '@shell/utils/versions';
35+
import { getPluginChartVersion, getPluginChartVersionLabel } from '@shell/utils/uiplugins';
3536
3637
const MAX_DESCRIPTION_LENGTH = 200;
3738
@@ -272,12 +273,14 @@ export default {
272273
item.certified = latestCompatible?.annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER;
273274
274275
item.displayVersion = latestCompatible.version;
276+
item.displayVersionLabel = getPluginChartVersionLabel(latestCompatible);
275277
item.icon = latestCompatible.icon;
276278
} else {
277279
item.experimental = uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.EXPERIMENTAL, 'true');
278280
item.certified = uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.CERTIFIED, CATALOG_ANNOTATIONS._RANCHER);
279281
280282
item.displayVersion = item.versions?.[0]?.version;
283+
item.displayVersionLabel = getPluginChartVersionLabel(item.versions?.[0]);
281284
item.icon = chart.icon || latestCompatible?.annotations?.['catalog.cattle.io/ui-icon'];
282285
}
283286
@@ -318,17 +321,18 @@ export default {
318321
319322
const label = rancher.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME] || p.name;
320323
const item = {
321-
name: p.name,
324+
name: p.name,
322325
label,
323-
description: p.metadata?.description,
324-
icon: p.metadata?.icon,
325-
id: p.id,
326-
versions: [],
327-
displayVersion: p.metadata?.version || '-',
328-
installed: true,
329-
builtin: !!p.builtin,
330-
experimental: rancher?.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true',
331-
certified: rancher?.annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER
326+
description: p.metadata?.description,
327+
icon: p.metadata?.icon,
328+
id: p.id,
329+
versions: [],
330+
displayVersion: p.metadata?.version,
331+
displayVersionLabel: p.metadata?.version || '-',
332+
installed: true,
333+
builtin: !!p.builtin,
334+
experimental: rancher?.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true',
335+
certified: rancher?.annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER
332336
};
333337
334338
// Built-in plugins can chose to be hidden - used where we implement as extensions
@@ -347,35 +351,42 @@ export default {
347351
chart.installed = true;
348352
chart.uiplugin = p;
349353
chart.displayVersion = p.version;
354+
let displayVersionLabel = p.version;
350355
351356
// Can't do this here
352357
chart.installing = this.installing[chart.name];
353358
354359
// Check for upgrade
355-
// Use the currently installed version's metadata to show/hide the experimental and certified labels
356-
if (chart.installableVersions?.length && p.version !== chart.installableVersions?.[0]?.version) {
357-
const installedVersion = (chart.installableVersions || []).find((v) => v?.version === p.version);
360+
const latestInstallableVersion = chart.installableVersions?.[0];
361+
362+
if (latestInstallableVersion && p.version !== (latestInstallableVersion.appVersion ?? latestInstallableVersion.version)) {
363+
// Use the currently installed version's metadata to show/hide the experimental and certified labels
364+
const installedVersion = (chart.installableVersions || []).find((v) => (v.appVersion ?? v.version) === p.version);
358365
359366
if (installedVersion) {
360367
chart.experimental = installedVersion?.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true';
361368
chart.certified = installedVersion?.annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER;
369+
displayVersionLabel = getPluginChartVersionLabel(installedVersion);
362370
}
363371
364-
chart.upgrade = chart.installableVersions[0].version;
372+
chart.upgrade = getPluginChartVersionLabel(latestInstallableVersion);
365373
}
374+
375+
chart.displayVersion = displayVersionLabel;
366376
} else {
367377
// No chart, so add a card for the plugin based on its Custom resource being present
368378
const item = {
369-
name: p.name,
370-
label: p.name,
371-
description: p.description || '-',
372-
id: `${ p.name }-${ p.version }`,
373-
versions: [],
374-
displayVersion: p.version || '-',
375-
installed: true,
376-
installing: false,
377-
builtin: false,
378-
uiplugin: p,
379+
name: p.name,
380+
label: p.name,
381+
description: p.description || '-',
382+
id: `${ p.name }-${ p.version }`,
383+
versions: [],
384+
displayVersion: p.version,
385+
displayVersionLabel: p.version || '-',
386+
installed: true,
387+
installing: false,
388+
builtin: false,
389+
uiplugin: p,
379390
};
380391
381392
all.push(item);
@@ -937,7 +948,7 @@ export default {
937948
-
938949
</span>
939950
<span v-else>
940-
<span>{{ plugin.displayVersion }}</span>
951+
<span>{{ plugin.displayVersionLabel }}</span>
941952
<span
942953
v-if="plugin.upgrade"
943954
v-clean-tooltip="t('plugins.upgradeAvailable')"

shell/types/uiplugins.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
export type VersionCompatibility = {
2+
isVersionCompatible: boolean;
3+
versionIncompatibilityData: any;
4+
};
5+
6+
export type ChartVersion = {
7+
name: string;
8+
version: string;
9+
description: string;
10+
icon: string;
11+
apiVersion: string;
12+
appVersion: string;
13+
annotations: {
14+
[key: string]: string;
15+
};
16+
type: string;
17+
urls: string[];
18+
created: string;
19+
digest: string;
20+
key: string;
21+
repoType: string;
22+
repoName: string;
23+
};
24+
25+
export type Version = ChartVersion & VersionCompatibility;
26+
27+
export type Chart = {
28+
key: string;
29+
type: string;
30+
id: string;
31+
certified: string;
32+
sideLabel?: string;
33+
repoType: string;
34+
repoName: string;
35+
repoNameDisplay: string;
36+
certifiedSort: number;
37+
icon: string;
38+
color?: string;
39+
chartType: string;
40+
chartName: string;
41+
chartNameDisplay: string;
42+
chartDescription: string;
43+
repoKey: string;
44+
versions: ChartVersion[];
45+
categories: any[];
46+
deprecated: boolean;
47+
experimental: boolean;
48+
hidden: boolean;
49+
targetNamespace: string;
50+
scope: string;
51+
provides: any[];
52+
windowsIncompatible: boolean;
53+
deploysOnWindows: boolean;
54+
};
55+
56+
export type Plugin = {
57+
name: string;
58+
label: string;
59+
description: string;
60+
id: string;
61+
versions: Version[];
62+
installed: boolean;
63+
builtin: boolean;
64+
experimental: boolean;
65+
certified: boolean;
66+
chart: Chart;
67+
incompatibilityMessage: string;
68+
installableVersions: ChartVersion[];
69+
displayVersion: string;
70+
pluginVersionLabel: string;
71+
icon?: string;
72+
helmError: boolean;
73+
};

shell/utils/uiplugins.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { matchesSomeRegex } from '@shell/utils/string';
22
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
33
import { CATALOG } from '@shell/config/types';
44
import { UI_PLUGIN_BASE_URL, isSupportedChartVersion } from '@shell/config/uiplugins';
5+
import { Plugin, Version } from '@shell/types/uiplugins';
56

67
const MAX_RETRIES = 10;
78
const RETRY_WAIT = 2500;
@@ -343,3 +344,22 @@ export async function onExtensionsReady(store: any) {
343344

344345
await store.dispatch('uiplugins/setReady', true);
345346
}
347+
348+
/**
349+
* Finds a Helm Chart version which matches plugin displayVersion. First it checks against Chart.appVersion and
350+
* falls back to Chart.version if appVersion is not present.
351+
*
352+
* @param plugin A data object constructed from UIPlugin and Helm Chart versions
353+
* @returns string Helm Chart version
354+
*/
355+
export function getPluginChartVersion(plugin?: Plugin) {
356+
const pluginVersion = plugin?.displayVersion;
357+
358+
return plugin?.versions?.find((v) => pluginVersion === (v.appVersion ?? v.version))?.version ?? pluginVersion;
359+
}
360+
361+
export function getPluginChartVersionLabel(version: Version) {
362+
if (version.appVersion === version.version) return `${ version.version }`;
363+
364+
return `${ version.appVersion } (${ version.version })`;
365+
}

0 commit comments

Comments
 (0)