mirror of https://github.com/rancher/dashboard.git
215 lines
6.8 KiB
JavaScript
215 lines
6.8 KiB
JavaScript
import { compatibleVersionsFor, APP_UPGRADE_STATUS } from '@shell/store/catalog';
|
||
import {
|
||
REPO_TYPE, REPO, CHART, VERSION, _FLAGGED, HIDE_SIDE_NAV, CATEGORY, TAG, DEPRECATED as DEPRECATED_QUERY
|
||
} from '@shell/config/query-params';
|
||
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
||
import SteveModel from '@shell/plugins/steve/steve-class';
|
||
import { CATALOG, ZERO_TIME } from '@shell/config/types';
|
||
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
|
||
import day from 'dayjs';
|
||
|
||
export default class Chart extends SteveModel {
|
||
queryParams(from, hideSideNav) {
|
||
let version;
|
||
const chartVersions = this.versions;
|
||
const currentCluster = this.$rootGetters['currentCluster'];
|
||
const workerOSs = currentCluster?.workerOSs;
|
||
const compatibleVersions = compatibleVersionsFor(this, workerOSs);
|
||
|
||
if (compatibleVersions.length) {
|
||
version = compatibleVersions[0].version;
|
||
} else {
|
||
version = chartVersions[0].version;
|
||
}
|
||
|
||
const out = {
|
||
[REPO_TYPE]: this.repoType,
|
||
[REPO]: this.repoName,
|
||
[CHART]: this.chartName,
|
||
[VERSION]: version,
|
||
};
|
||
|
||
if (this.deprecated) {
|
||
out[DEPRECATED_QUERY] = true;
|
||
}
|
||
|
||
if ( from ) {
|
||
out[from] = _FLAGGED;
|
||
}
|
||
|
||
if (hideSideNav) {
|
||
out[HIDE_SIDE_NAV] = _FLAGGED;
|
||
}
|
||
|
||
return out;
|
||
}
|
||
|
||
goToInstall(from, clusterId, hideSideNav) {
|
||
const query = this.queryParams(from, hideSideNav);
|
||
const currentCluster = this.$rootGetters['currentCluster'];
|
||
|
||
this.currentRouter().push({
|
||
name: 'c-cluster-apps-charts-install',
|
||
params: { cluster: clusterId || currentCluster?.id || BLANK_CLUSTER },
|
||
query,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Returns the list of installed apps that match this chart by:
|
||
* - chart name
|
||
* - repository name
|
||
* - and either:
|
||
* - the home URL matches the latest version’s home URL
|
||
* - or version + home URL match any other known version
|
||
*
|
||
* Inverse logic of `matchingCharts` in `catalog.cattle.io.app.js`.
|
||
*
|
||
* @returns {Array<Object>} List of matching installed app objects.
|
||
*/
|
||
get matchingInstalledApps() {
|
||
const latestVersion = this.versions?.[0] || [];
|
||
const appHome = latestVersion?.home;
|
||
const installedApps = this.$rootGetters['cluster/all'](CATALOG.APP);
|
||
|
||
return installedApps.filter((installedApp) => {
|
||
const metadata = installedApp?.spec?.chart?.metadata;
|
||
const name = metadata?.name;
|
||
const version = metadata?.version;
|
||
const home = metadata?.home;
|
||
|
||
const repoName = metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_NAME] ||
|
||
installedApp?.metadata?.labels?.[CATALOG_ANNOTATIONS.CLUSTER_REPO_NAME];
|
||
|
||
// name and repo should match
|
||
if (name !== this.chartName || !repoName || repoName !== this.repoName) {
|
||
return false;
|
||
}
|
||
|
||
// match by comparing home URL in the latest version vs home URL from the installed app
|
||
if (appHome && home === appHome) {
|
||
return true;
|
||
}
|
||
|
||
// match by version + home for the rest
|
||
return this.versions?.some((v) => v.version === version && home === appHome);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Determines if the chart is installed by checking if exactly one matching installed app is found.
|
||
*
|
||
* @returns {boolean} `true` if the chart is currently installed.
|
||
*/
|
||
get isInstalled() {
|
||
return this.matchingInstalledApps.length === 1;
|
||
}
|
||
|
||
/**
|
||
* Determines if the installed app has a single available upgrade.
|
||
* Requires the chart to be installed.
|
||
*
|
||
* @returns {boolean} `true` if the app is installed and has a single upgrade available.
|
||
*/
|
||
get upgradeable() {
|
||
return this.isInstalled && this.matchingInstalledApps[0].upgradeAvailable === APP_UPGRADE_STATUS.SINGLE_UPGRADE;
|
||
}
|
||
|
||
/**
|
||
* Builds structured metadata for display in RcItemCard.vue:
|
||
* - Sub-header (version and last updated)
|
||
* - Footer (repository, categories, tags)
|
||
* - Status indicators (e.g. deprecated, upgradeable, installed)
|
||
*
|
||
* @returns {Object} Card content object with `subHeaderItems`, `footerItems`, and `statuses` arrays.
|
||
*/
|
||
get cardContent() {
|
||
if (!this._cardContent) {
|
||
const latestVersion = this.versions?.[0] || {};
|
||
const subHeaderItems = [];
|
||
|
||
if (latestVersion) {
|
||
const hasZeroTime = latestVersion.created === ZERO_TIME;
|
||
|
||
subHeaderItems.push({
|
||
icon: 'icon-version-alt',
|
||
iconTooltip: { key: 'tableHeaders.version' },
|
||
label: latestVersion.version
|
||
});
|
||
|
||
const lastUpdatedItem = {
|
||
icon: 'icon-refresh-alt',
|
||
iconTooltip: { key: 'tableHeaders.lastUpdated' },
|
||
label: hasZeroTime ? this.t('generic.na') : day(latestVersion.created).format('MMM D, YYYY')
|
||
};
|
||
|
||
if (hasZeroTime) {
|
||
lastUpdatedItem.labelTooltip = this.t('catalog.charts.appChartCard.subHeaderItem.missingVersionDate');
|
||
}
|
||
|
||
subHeaderItems.push(lastUpdatedItem);
|
||
}
|
||
|
||
const footerItems = [
|
||
{
|
||
type: REPO,
|
||
icon: 'icon-repository-alt',
|
||
iconTooltip: { key: 'tableHeaders.repoName' },
|
||
labels: [this.repoNameDisplay],
|
||
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.repo') }, true)
|
||
}
|
||
];
|
||
|
||
if (this.categories.length) {
|
||
footerItems.push( {
|
||
type: CATEGORY,
|
||
icon: 'icon-category-alt',
|
||
iconTooltip: { key: 'generic.category' },
|
||
labels: this.categories,
|
||
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.category') }, true)
|
||
});
|
||
}
|
||
|
||
if (this.tags.length) {
|
||
footerItems.push({
|
||
type: TAG,
|
||
icon: 'icon-tag-alt',
|
||
iconTooltip: { key: 'generic.tags' },
|
||
labels: this.tags,
|
||
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.tag') }, true)
|
||
});
|
||
}
|
||
|
||
const statuses = [];
|
||
|
||
if (this.deprecated) {
|
||
statuses.push({
|
||
icon: 'icon-alert-alt', color: 'error', tooltip: { key: 'generic.deprecated' }
|
||
});
|
||
}
|
||
|
||
if (this.upgradeable) {
|
||
statuses.push({
|
||
icon: 'icon-upgrade-alt', color: 'info', tooltip: { key: 'generic.upgradeable' }
|
||
});
|
||
}
|
||
|
||
if (this.isInstalled) {
|
||
const installedVersion = this.matchingInstalledApps[0]?.spec?.chart?.metadata?.version;
|
||
|
||
statuses.push({
|
||
icon: 'icon-confirmation-alt', color: 'success', tooltip: { text: `${ this.t('generic.installed') } (${ installedVersion })` }
|
||
});
|
||
}
|
||
|
||
this._cardContent = {
|
||
subHeaderItems,
|
||
footerItems,
|
||
statuses
|
||
};
|
||
}
|
||
|
||
return this._cardContent;
|
||
}
|
||
}
|