-
+
diff --git a/dashboard/src/components/UpgradeForm/UpgradeForm.test.tsx b/dashboard/src/components/UpgradeForm/UpgradeForm.test.tsx
index 5684125262e..c32e8677bf0 100644
--- a/dashboard/src/components/UpgradeForm/UpgradeForm.test.tsx
+++ b/dashboard/src/components/UpgradeForm/UpgradeForm.test.tsx
@@ -304,6 +304,49 @@ it("defaults the upgrade version to the current version", () => {
expect(wrapper.find(DeploymentFormBody).prop("packageVersion")).toBe("1.0.0");
});
+it("uses the selected version passed in the component's props", () => {
+ const mockDispatch = jest.fn().mockReturnValue(true);
+ jest.spyOn(ReactRedux, "useDispatch").mockReturnValue(mockDispatch);
+ const fetchAndSelectAvailablePackageDetail = jest.fn();
+ actions.packages.fetchAndSelectAvailablePackageDetail = fetchAndSelectAvailablePackageDetail;
+
+ const state = {
+ ...defaultStore,
+ apps: {
+ selected: installedPkgDetail,
+ selectedDetails: availablePkgDetail,
+ isFetching: false,
+ } as IAppState,
+ packages: {
+ selected: {
+ ...selectedPkg,
+ versions: [] as PackageAppVersion[],
+ },
+ } as IPackageState,
+ };
+
+ mountWrapper(
+ getStore({ ...state }),
+
+
+ ,
+
+ ,
+ );
+
+ expect(fetchAndSelectAvailablePackageDetail).toHaveBeenCalledWith(
+ {
+ context: {
+ cluster: defaultProps.cluster,
+ namespace: defaultProps.repoNamespace,
+ },
+ identifier: defaultProps.packageId,
+ plugin: defaultProps.plugin,
+ },
+ "1.5.0",
+ );
+});
+
it("forwards the appValues when modified", () => {
const state = {
...defaultStore,
@@ -384,7 +427,7 @@ it("triggers an upgrade when submitting the form", async () => {
);
expect(mockDispatch).toHaveBeenCalledWith({
payload: {
- args: [url.app.apps.get(installedPkgDetail.installedPackageRef)],
+ args: [url.app.apps.get(installedPkgDetail.installedPackageRef!)],
method: "push",
},
type: "@@router/CALL_HISTORY_METHOD",
diff --git a/dashboard/src/components/UpgradeForm/UpgradeForm.tsx b/dashboard/src/components/UpgradeForm/UpgradeForm.tsx
index acceb05fc86..492336f98ca 100644
--- a/dashboard/src/components/UpgradeForm/UpgradeForm.tsx
+++ b/dashboard/src/components/UpgradeForm/UpgradeForm.tsx
@@ -7,28 +7,20 @@ import PackageHeader from "components/PackageHeader/PackageHeader";
import PackageVersionSelector from "components/PackageHeader/PackageVersionSelector";
import { push } from "connected-react-router";
import * as jsonpatch from "fast-json-patch";
-import {
- AvailablePackageDetail,
- InstalledPackageDetail,
-} from "gen/kubeappsapis/core/packages/v1alpha1/packages";
import * as yaml from "js-yaml";
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Action } from "redux";
import { ThunkDispatch } from "redux-thunk";
import { deleteValue, setValue } from "../../shared/schema";
-import { IPackageState, IStoreState } from "../../shared/types";
+import { IStoreState } from "../../shared/types";
import * as url from "../../shared/url";
import DeploymentFormBody from "../DeploymentFormBody/DeploymentFormBody";
import LoadingWrapper from "../LoadingWrapper/LoadingWrapper";
import "./UpgradeForm.css";
export interface IUpgradeFormProps {
- installedAppAvailablePackageDetail: AvailablePackageDetail;
- installedAppInstalledPackageDetail: InstalledPackageDetail;
- selectedPackage: IPackageState["selected"];
- chartsIsFetching: boolean;
- error?: Error;
+ version?: string;
}
function applyModifications(mods: jsonpatch.Operation[], values: string) {
@@ -47,7 +39,7 @@ function applyModifications(mods: jsonpatch.Operation[], values: string) {
return values;
}
-function UpgradeForm() {
+function UpgradeForm(props: IUpgradeFormProps) {
const dispatch: ThunkDispatch = useDispatch();
const {
@@ -89,12 +81,22 @@ function UpgradeForm() {
),
);
}
+ // If a version has been manually selected (eg. in the URL), fetch it explicitly
+ if (props.version) {
+ dispatch(
+ actions.packages.fetchAndSelectAvailablePackageDetail(
+ installedAppInstalledPackageDetail?.availablePackageRef,
+ props.version,
+ ),
+ );
+ }
}
}, [
dispatch,
installedAppInstalledPackageDetail?.availablePackageRef,
selectedPackage.versions.length,
installedAppAvailablePackageDetail,
+ props.version,
]);
useEffect(() => {
diff --git a/dashboard/src/containers/RoutesContainer/Routes.tsx b/dashboard/src/containers/RoutesContainer/Routes.tsx
index 8280e49ed94..d1e402e042f 100644
--- a/dashboard/src/containers/RoutesContainer/Routes.tsx
+++ b/dashboard/src/containers/RoutesContainer/Routes.tsx
@@ -27,18 +27,19 @@ const privateRoutes = {
"/c/:cluster/ns/:namespace/apps": AppList,
"/c/:cluster/ns/:namespace/apps/:pluginName/:pluginVersion/:releaseName": AppView,
"/c/:cluster/ns/:namespace/apps/:pluginName/:pluginVersion/:releaseName/upgrade": AppUpgrade,
- "/c/:cluster/ns/:namespace/apps/new/:repo/:pluginName/:pluginVersion/:id/versions/:version":
+ "/c/:cluster/ns/:namespace/apps/:pluginName/:pluginVersion/:releaseName/upgrade/:version":
+ AppUpgrade,
+ "/c/:cluster/ns/:namespace/apps/new/:pluginName/:pluginVersion/:packageId/versions/:packageVersion":
DeploymentForm,
- "/c/:cluster/ns/:namespace/apps/new-from-:global(global)/:repo/:pluginName/:pluginVersion/:id/versions/:version":
+ "/c/:cluster/ns/:namespace/apps/new-from-:global(global)/:pluginName/:pluginVersion/:packageId/versions/:packageVersion":
DeploymentForm,
"/c/:cluster/ns/:namespace/catalog": Catalog,
- "/c/:cluster/ns/:namespace/catalog/:repo": Catalog,
- "/c/:cluster/ns/:namespace/packages/:repo/:pluginName/:pluginVersion/:id": PackageView,
- "/c/:cluster/ns/:namespace/packages/:repo/:pluginName/:pluginVersion/:id/versions/:version":
+ "/c/:cluster/ns/:namespace/packages/:pluginName/:pluginVersion/:packageId": PackageView,
+ "/c/:cluster/ns/:namespace/packages/:pluginName/:pluginVersion/:packageId/versions/:packageVersion":
PackageView,
- "/c/:cluster/ns/:namespace/:global(global)-packages/:repo/:pluginName/:pluginVersion/:id":
+ "/c/:cluster/ns/:namespace/:global(global)-packages/:pluginName/:pluginVersion/:packageId":
PackageView,
- "/c/:cluster/ns/:namespace/:global(global)-packages/:repo/:pluginName/:pluginVersion/:id/versions/:version":
+ "/c/:cluster/ns/:namespace/:global(global)-packages/:pluginName/:pluginVersion/:packageId/versions/:packageVersion":
PackageView,
"/c/:cluster/ns/:namespace/operators": OperatorsListContainer,
"/c/:cluster/ns/:namespace/operators/:operator": OperatorViewContainer,
diff --git a/dashboard/src/reducers/apps.ts b/dashboard/src/reducers/apps.ts
index c6b9c9dc3f2..3423b38b130 100644
--- a/dashboard/src/reducers/apps.ts
+++ b/dashboard/src/reducers/apps.ts
@@ -16,7 +16,12 @@ const appsReducer = (
): IAppState => {
switch (action.type) {
case getType(actions.apps.requestApps):
- return { ...state, isFetching: true };
+ return {
+ ...state,
+ isFetching: true,
+ selected: undefined,
+ selectedDetails: undefined,
+ };
case getType(actions.apps.errorApp):
return { ...state, isFetching: false, error: action.payload };
case getType(actions.apps.selectApp):
diff --git a/dashboard/src/shared/url.ts b/dashboard/src/shared/url.ts
index 9b357b99a2a..d04e266d500 100644
--- a/dashboard/src/shared/url.ts
+++ b/dashboard/src/shared/url.ts
@@ -1,51 +1,55 @@
import {
- AvailablePackageDetail,
+ AvailablePackageReference,
InstalledPackageReference,
} from "gen/kubeappsapis/core/packages/v1alpha1/packages";
import { Plugin } from "gen/kubeappsapis/core/plugins/v1alpha1/plugins";
-import { IRepo } from "./types";
export const app = {
apps: {
new: (
cluster: string,
namespace: string,
- availablePackageDetail: AvailablePackageDetail,
- version: string,
- globalNamespace: string,
plugin: Plugin,
+ packageId: string,
+ version: string,
+ isGlobal: boolean,
) => {
- const repoNamespace = availablePackageDetail.availablePackageRef?.context?.namespace;
- const newSegment = globalNamespace !== repoNamespace ? "new" : "new-from-global";
- // TODO(agamez): get the repo name once available
- // https://github.com/kubeapps/kubeapps/issues/3165#issuecomment-884574732
- const repoName =
- availablePackageDetail.availablePackageRef?.identifier.split("/")?.[0] ?? globalNamespace;
- return `/c/${cluster}/ns/${namespace}/apps/${newSegment}/${repoName}/${plugin.name}/${
- plugin.version
- }/${encodeURIComponent(availablePackageDetail.name)}/versions/${version}`;
+ const globalSegment = isGlobal ? "new-from-global" : "new";
+ return `/c/${cluster}/ns/${namespace}/apps/${globalSegment}/${plugin?.name}/${
+ plugin?.version
+ }/${encodeURIComponent(packageId)}/versions/${version}`;
},
list: (cluster?: string, namespace?: string) => `/c/${cluster}/ns/${namespace}/apps`,
- get: (ref?: InstalledPackageReference) =>
- `${app.apps.list(ref?.context?.cluster, ref?.context?.namespace)}/${ref?.plugin?.name}/${
- ref?.plugin?.version
- }/${ref?.identifier}`,
- upgrade: (ref?: InstalledPackageReference) => `${app.apps.get(ref)}/upgrade`,
+ get: (installedPackageReference: InstalledPackageReference) => {
+ const pkgCluster = installedPackageReference?.context?.cluster;
+ const pkgNamespace = installedPackageReference?.context?.namespace;
+ const pkgPluginName = installedPackageReference?.plugin?.name;
+ const pkgPluginVersion = installedPackageReference?.plugin?.version;
+ const pkgId = installedPackageReference?.identifier || "";
+ return `${app.apps.list(
+ pkgCluster,
+ pkgNamespace,
+ )}/${pkgPluginName}/${pkgPluginVersion}/${pkgId}`;
+ },
+ upgrade: (ref: InstalledPackageReference) => `${app.apps.get(ref)}/upgrade`,
+ upgradeTo: (ref: InstalledPackageReference, version?: string) =>
+ `${app.apps.get(ref)}/upgrade/${version}`,
},
catalog: (cluster: string, namespace: string) => `/c/${cluster}/ns/${namespace}/catalog`,
packages: {
get: (
cluster: string,
namespace: string,
- packageName: string,
- repo: IRepo,
- globalNamespace: string,
- plugin: Plugin,
+ availablePackageReference: AvailablePackageReference,
+ isGlobal: boolean,
) => {
- const packagesSegment = globalNamespace === repo.namespace ? "global-packages" : "packages";
- return `/c/${cluster}/ns/${namespace}/${packagesSegment}/${repo.name}/${plugin.name}/${
- plugin.version
- }/${encodeURIComponent(packageName)}`;
+ const pkgPluginName = availablePackageReference?.plugin?.name;
+ const pkgPluginVersion = availablePackageReference?.plugin?.version;
+ const pkgId = availablePackageReference?.identifier || "";
+ const globalSegment = isGlobal ? "global-packages" : "packages";
+ return `/c/${cluster}/ns/${namespace}/${globalSegment}/${pkgPluginName}/${pkgPluginVersion}/${encodeURIComponent(
+ pkgId,
+ )}`;
},
},
operators: {