mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Making apiBase injectable (#6022)
* Making apiBase injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert all of Helm functions to be DI Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make PortForward's use of apiBase fully injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert all metric requests to be injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Replace resource applier with injectables Signed-off-by: Sebastian Malton <sebastian@malton.name> * Switch KubeJsonApi.forCluster to be injectable but do not use Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert the rest of shell sessions to be DI-ed - This is a prerequesit for using the new createKubeJsonApiForClusterInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Use new createKubeJsonApiForClusterInjectable for openNodeShellSession Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make KubeconfigDialog injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove jest-fetch-mock and make fetch injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests with new global override Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add new injectable for create KubeJsonApi and JsonApi instances Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix showing-details-for-helm-release behavioural tests - Remove HelmChartStore in favour of all injectables - Create a model for UpgradeChartDockTab Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix show details and updating helm releases tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix residual typing issues related to metrics Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix crash on load due to circular dependency Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix create resource tab not working Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove legacy apiBase global Signed-off-by: Sebastian Malton <sebastian@malton.name> * Introduce and use isDebuggingInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Introduce and use windowLocationInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove global legacy apiKube Signed-off-by: Sebastian Malton <sebastian@malton.name> * Improve injectable filenames compared to the injectables inside Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove modifying input in requestActivePortForwardInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Introduce and use get(Milli)SecondsFromUnixEpochInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Switch to non-reactive way of gettting possible helm release versions Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix typo Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix bug in KubeApi constructor Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert all KubeApi related tests to use asyncFn Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix unit tests after introducing new injectables that have side effects Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix bad rebase causing tests to fail Signed-off-by: Sebastian Malton <sebastian@malton.name> * Improve expects for multiple field values Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix crash will looking up api refs Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix breaking change on KubeApi.list Signed-off-by: Sebastian Malton <sebastian@malton.name> * Better fix for formatting urls Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove injectable for time since we should just use useMockTime Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add happy path behavioural tests for upgrade chart tab Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove debug message Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix showing-details-for-helm-release tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix installing-helm-chart-from-new-tab tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests relating to hosted cluster id Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots to recent changes in master Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> * Reupdated upgrade chart new tab test snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix flakiness in unit test when using <Animated> Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix flakiness and improve tests for DeleteClusterDialog Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix kubeconfig-sync tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix <Extensions> tests by removing mockFs and making everything injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix build issues Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix getElectronAppPathInjectable override not returning absolute paths - Also fixes the listing-active-helm-repos-in-prefs tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Replace all uses of getAbsolutePath with joinPaths as it is more correct and less confusing Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix opening application window tests by making override properly absolute Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots relating no longer using getAbsolutePath Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix and add behavioural tests for RenderDelay Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix extension discovery tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix test flakiness because of path side effects, propagate uses to as many places Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix extension-discovery tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add global override to fix some tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Rewrite and fix implementation of KubeconfigManager and its tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests by global override pathExists Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix unit tests failing on windows by using injectable verions of path functions Signed-off-by: Sebastian Malton <sebastian@malton.name> * Attempt to fix test timeout by using runInAction Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots after rebase Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots after rebase Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests after rebase Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix setupIpcMainHandlers usage Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> Co-authored-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
367 files changed
+16701
-5302
No files matched your search
@@ -3,49 +3,35 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import path from "path";
|
||||
import { hasCorrectExtension } from "./has-correct-extension";
|
||||
import readFileInjectable from "../../../../common/fs/read-file.injectable";
|
||||
import readDirInjectable from "../../../../common/fs/read-dir.injectable";
|
||||
import readDirectoryInjectable from "../../../../common/fs/read-directory.injectable";
|
||||
import type { RawTemplates } from "./create-resource-templates.injectable";
|
||||
import type { GetAbsolutePath } from "../../../../common/path/get-absolute-path.injectable";
|
||||
import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable";
|
||||
import staticFilesDirectoryInjectable from "../../../../common/vars/static-files-directory.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
readDir: (dirPath: string) => Promise<string[]>;
|
||||
readFile: (filePath: string) => Promise<string>;
|
||||
getAbsolutePath: GetAbsolutePath;
|
||||
staticFilesDirectory: string;
|
||||
}
|
||||
|
||||
async function getTemplates({ readDir, readFile, getAbsolutePath, staticFilesDirectory }: Dependencies) {
|
||||
const templatesFolder = getAbsolutePath(staticFilesDirectory, "../templates/create-resource");
|
||||
|
||||
/**
|
||||
* Mapping between file names and their contents
|
||||
*/
|
||||
const templates: [file: string, contents: string][] = [];
|
||||
|
||||
for (const dirEntry of await readDir(templatesFolder)) {
|
||||
if (hasCorrectExtension(dirEntry)) {
|
||||
templates.push([path.parse(dirEntry).name, await readFile(path.join(templatesFolder, dirEntry))]);
|
||||
}
|
||||
}
|
||||
|
||||
return templates;
|
||||
}
|
||||
import joinPathsInjectable from "../../../../common/path/join-paths.injectable";
|
||||
import parsePathInjectable from "../../../../common/path/parse.injectable";
|
||||
|
||||
const lensCreateResourceTemplatesInjectable = getInjectable({
|
||||
id: "lens-create-resource-templates",
|
||||
|
||||
instantiate: async (di): Promise<RawTemplates> => {
|
||||
const templates = await getTemplates({
|
||||
readFile: di.inject(readFileInjectable),
|
||||
readDir: di.inject(readDirInjectable),
|
||||
getAbsolutePath: di.inject(getAbsolutePathInjectable),
|
||||
staticFilesDirectory: di.inject(staticFilesDirectoryInjectable),
|
||||
});
|
||||
const readFile = di.inject(readFileInjectable);
|
||||
const readDir = di.inject(readDirectoryInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable);
|
||||
const parsePath = di.inject(parsePathInjectable);
|
||||
|
||||
/**
|
||||
* Mapping between file names and their contents
|
||||
*/
|
||||
const templates: [file: string, contents: string][] = [];
|
||||
const templatesFolder = joinPaths(staticFilesDirectory, "../templates/create-resource");
|
||||
|
||||
for (const dirEntry of await readDir(templatesFolder)) {
|
||||
if (hasCorrectExtension(dirEntry)) {
|
||||
templates.push([parsePath(dirEntry).name, await readFile(joinPaths(templatesFolder, dirEntry))]);
|
||||
}
|
||||
}
|
||||
|
||||
return ["lens", templates];
|
||||
},
|
||||
|
||||
@@ -3,101 +3,108 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { computed, observable } from "mobx";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import { delay, getOrInsert, isErrnoException, waitForPath } from "../../../utils";
|
||||
import { watch } from "chokidar";
|
||||
import { readFile } from "fs/promises";
|
||||
import logger from "../../../../common/logger";
|
||||
import { hasCorrectExtension } from "./has-correct-extension";
|
||||
import type { RawTemplates } from "./create-resource-templates.injectable";
|
||||
|
||||
const userTemplatesFolder = path.join(os.homedir(), ".k8slens", "templates");
|
||||
|
||||
function groupTemplates(templates: Map<string, string>): RawTemplates[] {
|
||||
const res = new Map<string, [string, string][]>();
|
||||
|
||||
for (const [filePath, contents] of templates) {
|
||||
const rawRelative = path.dirname(path.relative(userTemplatesFolder, filePath));
|
||||
const title = rawRelative === "."
|
||||
? "ungrouped"
|
||||
: rawRelative;
|
||||
|
||||
getOrInsert(res, title, []).push([path.parse(filePath).name, contents]);
|
||||
}
|
||||
|
||||
return [...res.entries()];
|
||||
}
|
||||
|
||||
function watchUserCreateResourceTemplates(): IComputedValue<RawTemplates[]> {
|
||||
/**
|
||||
* Map between filePaths and template contents
|
||||
*/
|
||||
const templates = observable.map<string, string>();
|
||||
|
||||
const onAddOrChange = async (filePath: string) => {
|
||||
if (!hasCorrectExtension(filePath)) {
|
||||
// ignore non yaml or json files
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const contents = await readFile(filePath, "utf-8");
|
||||
|
||||
templates.set(filePath, contents);
|
||||
} catch (error) {
|
||||
if (isErrnoException(error) && error.code === "ENOENT") {
|
||||
// ignore, file disappeared
|
||||
} else {
|
||||
logger.warn(`[USER-CREATE-RESOURCE-TEMPLATES]: encountered error while reading ${filePath}`, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
const onUnlink = (filePath: string) => {
|
||||
templates.delete(filePath);
|
||||
};
|
||||
|
||||
(async () => {
|
||||
for (let i = 1;; i *= 2) {
|
||||
try {
|
||||
await waitForPath(userTemplatesFolder);
|
||||
break;
|
||||
} catch (error) {
|
||||
logger.warn(`[USER-CREATE-RESOURCE-TEMPLATES]: encountered error while waiting for ${userTemplatesFolder} to exist, waiting and trying again`, error);
|
||||
await delay(i * 1000); // exponential backoff in seconds
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: There is technically a race condition here of the form "time-of-check to time-of-use"
|
||||
*/
|
||||
watch(userTemplatesFolder, {
|
||||
disableGlobbing: true,
|
||||
ignorePermissionErrors: true,
|
||||
usePolling: false,
|
||||
awaitWriteFinish: {
|
||||
pollInterval: 100,
|
||||
stabilityThreshold: 1000,
|
||||
},
|
||||
ignoreInitial: false,
|
||||
atomic: 150, // for "atomic writes"
|
||||
})
|
||||
.on("add", onAddOrChange)
|
||||
.on("change", onAddOrChange)
|
||||
.on("unlink", onUnlink)
|
||||
.on("error", error => {
|
||||
logger.warn(`[USER-CREATE-RESOURCE-TEMPLATES]: encountered error while watching files under ${userTemplatesFolder}`, error);
|
||||
});
|
||||
})();
|
||||
|
||||
return computed(() => groupTemplates(templates));
|
||||
}
|
||||
import joinPathsInjectable from "../../../../common/path/join-paths.injectable";
|
||||
import watchInjectable from "../../../../common/fs/watch/watch.injectable";
|
||||
import getRelativePathInjectable from "../../../../common/path/get-relative-path.injectable";
|
||||
import homeDirectoryPathInjectable from "../../../../common/os/home-directory-path.injectable";
|
||||
import getDirnameOfPathInjectable from "../../../../common/path/get-dirname.injectable";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import parsePathInjectable from "../../../../common/path/parse.injectable";
|
||||
|
||||
const userCreateResourceTemplatesInjectable = getInjectable({
|
||||
id: "user-create-resource-templates",
|
||||
instantiate: () => watchUserCreateResourceTemplates(),
|
||||
instantiate: (di) => {
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const watch = di.inject(watchInjectable);
|
||||
const getRelativePath = di.inject(getRelativePathInjectable);
|
||||
const homeDirectoryPath = di.inject(homeDirectoryPathInjectable);
|
||||
const getDirnameOfPath = di.inject(getDirnameOfPathInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const parsePath = di.inject(parsePathInjectable);
|
||||
|
||||
const userTemplatesFolder = joinPaths(homeDirectoryPath, ".k8slens", "templates");
|
||||
const groupTemplates = (templates: Map<string, string>): RawTemplates[] => {
|
||||
const res = new Map<string, [string, string][]>();
|
||||
|
||||
for (const [filePath, contents] of templates) {
|
||||
const rawRelative = getDirnameOfPath(getRelativePath(userTemplatesFolder, filePath));
|
||||
const title = rawRelative === "."
|
||||
? "ungrouped"
|
||||
: rawRelative;
|
||||
|
||||
getOrInsert(res, title, []).push([parsePath(filePath).name, contents]);
|
||||
}
|
||||
|
||||
return [...res.entries()];
|
||||
};
|
||||
|
||||
/**
|
||||
* Map between filePaths and template contents
|
||||
*/
|
||||
const templates = observable.map<string, string>();
|
||||
|
||||
const onAddOrChange = async (filePath: string) => {
|
||||
if (!hasCorrectExtension(filePath)) {
|
||||
// ignore non yaml or json files
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const contents = await readFile(filePath, "utf-8");
|
||||
|
||||
templates.set(filePath, contents);
|
||||
} catch (error) {
|
||||
if (isErrnoException(error) && error.code === "ENOENT") {
|
||||
// ignore, file disappeared
|
||||
} else {
|
||||
logger.warn(`[USER-CREATE-RESOURCE-TEMPLATES]: encountered error while reading ${filePath}`, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
const onUnlink = (filePath: string) => {
|
||||
templates.delete(filePath);
|
||||
};
|
||||
|
||||
(async () => {
|
||||
for (let i = 1;; i *= 2) {
|
||||
try {
|
||||
await waitForPath(userTemplatesFolder);
|
||||
break;
|
||||
} catch (error) {
|
||||
logger.warn(`[USER-CREATE-RESOURCE-TEMPLATES]: encountered error while waiting for ${userTemplatesFolder} to exist, waiting and trying again`, error);
|
||||
await delay(i * 1000); // exponential backoff in seconds
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: There is technically a race condition here of the form "time-of-check to time-of-use"
|
||||
*/
|
||||
watch(userTemplatesFolder, {
|
||||
disableGlobbing: true,
|
||||
ignorePermissionErrors: true,
|
||||
usePolling: false,
|
||||
awaitWriteFinish: {
|
||||
pollInterval: 100,
|
||||
stabilityThreshold: 1000,
|
||||
},
|
||||
ignoreInitial: false,
|
||||
atomic: 150, // for "atomic writes"
|
||||
})
|
||||
.on("add", onAddOrChange)
|
||||
.on("change", onAddOrChange)
|
||||
.on("unlink", onUnlink)
|
||||
.on("error", error => {
|
||||
logger.warn(`[USER-CREATE-RESOURCE-TEMPLATES]: encountered error while watching files under ${userTemplatesFolder}`, error);
|
||||
});
|
||||
})();
|
||||
|
||||
return computed(() => groupTemplates(templates));
|
||||
},
|
||||
});
|
||||
|
||||
export default userCreateResourceTemplatesInjectable;
|
||||
@@ -6,14 +6,13 @@
|
||||
import React from "react";
|
||||
import type { SelectOption } from "../../select";
|
||||
import { Select } from "../../select";
|
||||
import yaml from "js-yaml";
|
||||
import yaml, { dump } from "js-yaml";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import type { CreateResourceTabStore } from "./store";
|
||||
import { EditorPanel } from "../editor-panel";
|
||||
import { InfoPanel } from "../info-panel";
|
||||
import * as resourceApplierApi from "../../../../common/k8s-api/endpoints/resource-applier.api";
|
||||
import { Notifications } from "../../notifications";
|
||||
import logger from "../../../../common/logger";
|
||||
import type { ApiManager } from "../../../../common/k8s-api/api-manager";
|
||||
@@ -28,6 +27,8 @@ import type { GetDetailsUrl } from "../../kube-detail-params/get-details-url.inj
|
||||
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
|
||||
import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable";
|
||||
import navigateInjectable from "../../../navigation/navigate.injectable";
|
||||
import type { RequestKubeObjectCreation } from "../../../../common/k8s-api/endpoints/resource-applier.api/request-update.injectable";
|
||||
import requestKubeObjectCreationInjectable from "../../../../common/k8s-api/endpoints/resource-applier.api/request-update.injectable";
|
||||
|
||||
export interface CreateResourceProps {
|
||||
tabId: string;
|
||||
@@ -39,6 +40,7 @@ interface Dependencies {
|
||||
apiManager: ApiManager;
|
||||
navigate: Navigate;
|
||||
getDetailsUrl: GetDetailsUrl;
|
||||
requestKubeObjectCreation: RequestKubeObjectCreation;
|
||||
}
|
||||
|
||||
@observer
|
||||
@@ -68,7 +70,7 @@ class NonInjectedCreateResource extends React.Component<CreateResourceProps & De
|
||||
};
|
||||
|
||||
create = async (): Promise<void> => {
|
||||
const { apiManager, getDetailsUrl, navigate } = this.props;
|
||||
const { apiManager, getDetailsUrl, navigate, requestKubeObjectCreation } = this.props;
|
||||
|
||||
if (this.error || !this.data?.trim()) {
|
||||
// do not save when field is empty or there is an error
|
||||
@@ -84,7 +86,7 @@ class NonInjectedCreateResource extends React.Component<CreateResourceProps & De
|
||||
|
||||
const creatingResources = resources.map(async (resource) => {
|
||||
try {
|
||||
const data = await resourceApplierApi.update(resource);
|
||||
const data = await requestKubeObjectCreation(dump(resource));
|
||||
const { kind, apiVersion, metadata: { name, namespace }} = data;
|
||||
|
||||
const showDetails = () => {
|
||||
@@ -168,5 +170,6 @@ export const CreateResource = withInjectables<Dependencies, CreateResourceProps>
|
||||
apiManager: di.inject(apiManagerInjectable),
|
||||
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
||||
navigate: di.inject(navigateInjectable),
|
||||
requestKubeObjectCreation: di.inject(requestKubeObjectCreationInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -103,6 +103,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
|
||||
material="close"
|
||||
tooltip={`Close ${this.props.isMac ? "⌘+W" : "Ctrl+W"}`}
|
||||
onClick={close}
|
||||
data-testid={`dock-tab-close-for-${id}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { getChartValues } from "../../../../../common/k8s-api/endpoints/helm-charts.api";
|
||||
|
||||
export type CallForHelmChartValues = (
|
||||
repo: string,
|
||||
name: string,
|
||||
version: string
|
||||
) => Promise<string>;
|
||||
|
||||
const callForHelmChartValuesInjectable = getInjectable({
|
||||
id: "call-for-helm-chart-values",
|
||||
instantiate: (): CallForHelmChartValues => getChartValues,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default callForHelmChartValuesInjectable;
|
||||
@@ -5,36 +5,31 @@
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import installChartTabStoreInjectable from "./store.injectable";
|
||||
import { waitUntilDefined } from "../../../../common/utils";
|
||||
import type { CallForHelmChartValues } from "./chart-data/call-for-helm-chart-values.injectable";
|
||||
import callForHelmChartValuesInjectable from "./chart-data/call-for-helm-chart-values.injectable";
|
||||
import type { IChartInstallData, InstallChartTabStore } from "./store";
|
||||
import type { HelmChart } from "../../../../common/k8s-api/endpoints/helm-charts.api";
|
||||
import React from "react";
|
||||
import {
|
||||
action,
|
||||
computed,
|
||||
observable,
|
||||
runInAction,
|
||||
} from "mobx";
|
||||
import { action, computed, observable, runInAction } from "mobx";
|
||||
import assert from "assert";
|
||||
import type { CallForCreateHelmRelease } from "../../+helm-releases/create-release/call-for-create-helm-release.injectable";
|
||||
import callForCreateHelmReleaseInjectable from "../../+helm-releases/create-release/call-for-create-helm-release.injectable";
|
||||
import type { RequestCreateHelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api/request-create.injectable";
|
||||
import requestCreateHelmReleaseInjectable from "../../../../common/k8s-api/endpoints/helm-releases.api/request-create.injectable";
|
||||
import type { HelmReleaseUpdateDetails } from "../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||
import dockStoreInjectable from "../dock/store.injectable";
|
||||
import type { NavigateToHelmReleases } from "../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import navigateToHelmReleasesInjectable from "../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import type { SingleValue } from "react-select";
|
||||
import type { CallForHelmChartVersions } from "../../+helm-charts/details/versions/call-for-helm-chart-versions.injectable";
|
||||
import callForHelmChartVersionsInjectable from "../../+helm-charts/details/versions/call-for-helm-chart-versions.injectable";
|
||||
import type { RequestHelmChartValues } from "../../../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
||||
import requestHelmChartValuesInjectable from "../../../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
||||
import type { RequestHelmChartVersions } from "../../../../common/k8s-api/endpoints/helm-charts.api/request-versions.injectable";
|
||||
import requestHelmChartVersionsInjectable from "../../../../common/k8s-api/endpoints/helm-charts.api/request-versions.injectable";
|
||||
|
||||
const installChartModelInjectable = getInjectable({
|
||||
id: "install-chart-model",
|
||||
|
||||
instantiate: async (di, tabId: string) => {
|
||||
const store = di.inject(installChartTabStoreInjectable);
|
||||
const callForHelmChartValues = di.inject(callForHelmChartValuesInjectable);
|
||||
const callForHelmChartVersions = di.inject(callForHelmChartVersionsInjectable);
|
||||
const callForCreateHelmRelease = di.inject(callForCreateHelmReleaseInjectable);
|
||||
const requestHelmChartValues = di.inject(requestHelmChartValuesInjectable);
|
||||
const requestHelmChartVersions = di.inject(requestHelmChartVersionsInjectable);
|
||||
const callForCreateHelmRelease = di.inject(requestCreateHelmReleaseInjectable);
|
||||
const dockStore = di.inject(dockStoreInjectable);
|
||||
const navigateToHelmReleases = di.inject(navigateToHelmReleasesInjectable);
|
||||
const closeTab = () => dockStore.closeTab(tabId);
|
||||
@@ -49,8 +44,8 @@ const installChartModelInjectable = getInjectable({
|
||||
callForCreateHelmRelease,
|
||||
closeTab,
|
||||
navigateToHelmReleases,
|
||||
callForHelmChartValues,
|
||||
callForHelmChartVersions,
|
||||
requestHelmChartValues,
|
||||
requestHelmChartVersions,
|
||||
store,
|
||||
});
|
||||
|
||||
@@ -71,9 +66,9 @@ interface Dependencies {
|
||||
closeTab: () => void;
|
||||
navigateToHelmReleases: NavigateToHelmReleases;
|
||||
waitForChart: () => Promise<void>;
|
||||
callForCreateHelmRelease: CallForCreateHelmRelease;
|
||||
callForHelmChartValues: CallForHelmChartValues;
|
||||
callForHelmChartVersions: CallForHelmChartVersions;
|
||||
callForCreateHelmRelease: RequestCreateHelmRelease;
|
||||
requestHelmChartValues: RequestHelmChartValues;
|
||||
requestHelmChartVersions: RequestHelmChartVersions;
|
||||
store: InstallChartTabStore;
|
||||
}
|
||||
|
||||
@@ -127,7 +122,7 @@ export class InstallChartModel {
|
||||
this.configuration.isLoading.set(true);
|
||||
});
|
||||
|
||||
const configuration = await this.dependencies.callForHelmChartValues(
|
||||
const configuration = await this.dependencies.requestHelmChartValues(
|
||||
this.chart.repo,
|
||||
this.chart.name,
|
||||
version,
|
||||
@@ -193,13 +188,13 @@ export class InstallChartModel {
|
||||
await this.dependencies.waitForChart();
|
||||
|
||||
const [defaultConfiguration, versions] = await Promise.all([
|
||||
this.dependencies.callForHelmChartValues(
|
||||
this.dependencies.requestHelmChartValues(
|
||||
this.chart.repo,
|
||||
this.chart.name,
|
||||
this.chart.version,
|
||||
),
|
||||
|
||||
this.dependencies.callForHelmChartVersions(
|
||||
this.dependencies.requestHelmChartVersions(
|
||||
this.chart.repo,
|
||||
this.chart.name,
|
||||
),
|
||||
|
||||
@@ -3,23 +3,27 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IChartUpgradeData } from "./store.injectable";
|
||||
import upgradeChartTabStoreInjectable from "./store.injectable";
|
||||
import dockStoreInjectable from "../dock/store.injectable";
|
||||
import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||
import type { DockStore, DockTabCreateSpecific, TabId } from "../dock/store";
|
||||
import { TabKind } from "../dock/store";
|
||||
import type { UpgradeChartTabStore } from "./store";
|
||||
import { runInAction } from "mobx";
|
||||
import getRandomUpgradeChartTabIdInjectable from "./get-random-upgrade-chart-tab-id.injectable";
|
||||
import type { DockTabStore } from "../dock-tab-store/dock-tab.store";
|
||||
|
||||
interface Dependencies {
|
||||
upgradeChartStore: UpgradeChartTabStore;
|
||||
upgradeChartStore: DockTabStore<IChartUpgradeData>;
|
||||
dockStore: DockStore;
|
||||
getRandomId: () => string;
|
||||
}
|
||||
|
||||
const createUpgradeChartTab = ({ upgradeChartStore, dockStore, getRandomId }: Dependencies) => (release: HelmRelease, tabParams: DockTabCreateSpecific = {}): TabId => {
|
||||
const tabId = upgradeChartStore.getTabIdByRelease(release.getName());
|
||||
const tabId = upgradeChartStore.findTabIdFromData(val => (
|
||||
val.releaseName === release.getName()
|
||||
&& val.releaseNamespace === release.getNs()
|
||||
));
|
||||
|
||||
if (tabId) {
|
||||
dockStore.open();
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { UpgradeChartTabStore } from "./store";
|
||||
import createDockTabStoreInjectable from "../dock-tab-store/create-dock-tab-store.injectable";
|
||||
import createStorageInjectable from "../../../utils/create-storage/create-storage.injectable";
|
||||
|
||||
export interface IChartUpgradeData {
|
||||
releaseName: string;
|
||||
releaseNamespace: string;
|
||||
}
|
||||
|
||||
const upgradeChartTabStoreInjectable = getInjectable({
|
||||
id: "upgrade-chart-tab-store",
|
||||
@@ -13,9 +16,8 @@ const upgradeChartTabStoreInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const createDockTabStore = di.inject(createDockTabStoreInjectable);
|
||||
|
||||
return new UpgradeChartTabStore({
|
||||
createStorage: di.inject(createStorageInjectable),
|
||||
valuesStore: createDockTabStore<string>(),
|
||||
return createDockTabStore<IChartUpgradeData>({
|
||||
storageKey: "chart_releases",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { action, computed, makeObservable } from "mobx";
|
||||
import type { TabId } from "../dock/store";
|
||||
import type { DockTabStoreDependencies } from "../dock-tab-store/dock-tab.store";
|
||||
import { DockTabStore } from "../dock-tab-store/dock-tab.store";
|
||||
import { getReleaseValues } from "../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||
import assert from "assert";
|
||||
|
||||
export interface IChartUpgradeData {
|
||||
releaseName: string;
|
||||
releaseNamespace: string;
|
||||
}
|
||||
|
||||
export interface UpgradeChartTabStoreDependencies extends DockTabStoreDependencies {
|
||||
valuesStore: DockTabStore<string>;
|
||||
}
|
||||
|
||||
export class UpgradeChartTabStore extends DockTabStore<IChartUpgradeData> {
|
||||
@computed private get releaseNameReverseLookup(): Map<string, string> {
|
||||
return new Map(this.getAllData().map(([id, { releaseName }]) => [releaseName, id]));
|
||||
}
|
||||
|
||||
get values() {
|
||||
return this.dependencies.valuesStore;
|
||||
}
|
||||
|
||||
constructor(protected readonly dependencies: UpgradeChartTabStoreDependencies) {
|
||||
super(dependencies, {
|
||||
storageKey: "chart_releases",
|
||||
});
|
||||
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@action
|
||||
async reloadValues(tabId: TabId) {
|
||||
this.values.clearData(tabId); // reset
|
||||
const data = this.getData(tabId);
|
||||
|
||||
assert(data, "cannot reload values if no data");
|
||||
|
||||
const { releaseName, releaseNamespace } = data;
|
||||
const values = await getReleaseValues(releaseName, releaseNamespace, true);
|
||||
|
||||
this.values.setData(tabId, values);
|
||||
}
|
||||
|
||||
getTabIdByRelease(releaseName: string) {
|
||||
return this.releaseNameReverseLookup.get(releaseName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import { waitUntilDefined } from "../../../utils";
|
||||
import upgradeChartTabStoreInjectable from "./store.injectable";
|
||||
|
||||
const upgradeChartTabDataInjectable = getInjectable({
|
||||
id: "upgrade-chart-tab-data",
|
||||
instantiate: (di, tabId) => {
|
||||
const upgradeChartTabStore = di.inject(upgradeChartTabStoreInjectable);
|
||||
|
||||
return waitUntilDefined(() => upgradeChartTabStore.getData(tabId));
|
||||
},
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, tabId: string) => tabId,
|
||||
}),
|
||||
});
|
||||
|
||||
export default upgradeChartTabDataInjectable;
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import { asyncComputed } from "@ogre-tools/injectable-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { action, computed, observable, when } from "mobx";
|
||||
import type { SingleValue } from "react-select";
|
||||
import type { HelmChartVersion } from "../../+helm-charts/helm-charts/versions";
|
||||
import helmChartVersionsInjectable from "../../+helm-charts/helm-charts/versions.injectable";
|
||||
import releasesInjectable from "../../+helm-releases/releases.injectable";
|
||||
import updateReleaseInjectable from "../../+helm-releases/update-release/update-release.injectable";
|
||||
import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||
import requestHelmReleaseConfigurationInjectable from "../../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||
import { waitUntilDefined } from "../../../utils";
|
||||
import type { SelectOption } from "../../select";
|
||||
import type { DockTab } from "../dock/store";
|
||||
import upgradeChartTabDataInjectable from "./tab-data.injectable";
|
||||
|
||||
export interface UpgradeChartModel {
|
||||
readonly release: HelmRelease;
|
||||
readonly versionOptions: IComputedValue<SelectOption<HelmChartVersion>[]>;
|
||||
readonly configration: {
|
||||
readonly value: IComputedValue<string>;
|
||||
set: (value: string) => void;
|
||||
readonly error: IComputedValue<string | undefined>;
|
||||
setError: (error: unknown) => void;
|
||||
};
|
||||
readonly version: {
|
||||
readonly value: IComputedValue<HelmChartVersion | undefined>;
|
||||
set: (value: SingleValue<SelectOption<HelmChartVersion>>) => void;
|
||||
};
|
||||
submit: () => Promise<UpgradeChartSubmitResult>;
|
||||
}
|
||||
|
||||
export interface UpgradeChartSubmitResult {
|
||||
completedSuccessfully: boolean;
|
||||
}
|
||||
|
||||
const upgradeChartModelInjectable = getInjectable({
|
||||
id: "upgrade-chart-model",
|
||||
instantiate: async (di, tab): Promise<UpgradeChartModel> => {
|
||||
const releases = di.inject(releasesInjectable);
|
||||
const requestHelmReleaseConfiguration = di.inject(requestHelmReleaseConfigurationInjectable);
|
||||
const updateRelease = di.inject(updateReleaseInjectable);
|
||||
const tabData = await di.inject(upgradeChartTabDataInjectable, tab.id);
|
||||
|
||||
const release = await waitUntilDefined(() => (
|
||||
releases.value
|
||||
.get()
|
||||
.find(release => (
|
||||
release.getName() === tabData.releaseName
|
||||
&& release.getNs() === tabData.releaseNamespace
|
||||
))
|
||||
));
|
||||
const versions = di.inject(helmChartVersionsInjectable, release);
|
||||
const storedConfiguration = asyncComputed(() => requestHelmReleaseConfiguration(
|
||||
release.getName(),
|
||||
release.getNs(),
|
||||
true,
|
||||
), "");
|
||||
|
||||
await when(() => !versions.pending.get());
|
||||
|
||||
const configrationValue = observable.box<string>();
|
||||
const configrationEditError = observable.box<string>();
|
||||
const configration: UpgradeChartModel["configration"] = {
|
||||
value: computed(() => configrationValue.get() ?? storedConfiguration.value.get()),
|
||||
set: action((value) => {
|
||||
configrationValue.set(value);
|
||||
configrationEditError.set(undefined);
|
||||
}),
|
||||
error: computed(() => configrationEditError.get()),
|
||||
setError: action((error) => configrationEditError.set(String(error))),
|
||||
};
|
||||
const versionValue = observable.box<HelmChartVersion>(undefined, {
|
||||
deep: false,
|
||||
});
|
||||
const version: UpgradeChartModel["version"] = {
|
||||
value: computed(() => versionValue.get() ?? versions.value.get()[0]),
|
||||
set: action((option) => versionValue.set(option?.value)),
|
||||
};
|
||||
const versionOptions = computed(() => (
|
||||
versions.value
|
||||
.get()
|
||||
.map(version => ({
|
||||
value: version,
|
||||
label: `${version.repo}/${release.getChart()}-${version.version}`,
|
||||
}))
|
||||
));
|
||||
|
||||
return {
|
||||
release,
|
||||
versionOptions,
|
||||
configration,
|
||||
version,
|
||||
submit: async () => {
|
||||
const selectedVersion = version.value.get();
|
||||
|
||||
if (!selectedVersion || configrationEditError.get()) {
|
||||
return {
|
||||
completedSuccessfully: false,
|
||||
};
|
||||
}
|
||||
|
||||
await updateRelease(
|
||||
release.getName(),
|
||||
release.getNs(),
|
||||
{
|
||||
chart: release.getChart(),
|
||||
values: configration.value.get(),
|
||||
...selectedVersion,
|
||||
},
|
||||
);
|
||||
storedConfiguration.invalidate();
|
||||
|
||||
return {
|
||||
completedSuccessfully: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, tab: DockTab) => tab.id,
|
||||
}),
|
||||
});
|
||||
|
||||
export default upgradeChartModelInjectable;
|
||||
@@ -6,26 +6,19 @@
|
||||
import "./upgrade-chart.scss";
|
||||
|
||||
import React from "react";
|
||||
import { action, makeObservable, observable, reaction } from "mobx";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { observer } from "mobx-react";
|
||||
import { cssNames } from "../../../utils";
|
||||
import type { DockTab } from "../dock/store";
|
||||
import { InfoPanel } from "../info-panel";
|
||||
import type { UpgradeChartTabStore } from "./store";
|
||||
import { Spinner } from "../../spinner";
|
||||
import { Badge } from "../../badge";
|
||||
import { EditorPanel } from "../editor-panel";
|
||||
import { helmChartStore, type ChartVersion } from "../../+helm-charts/helm-chart.store";
|
||||
import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||
import type { SelectOption } from "../../select";
|
||||
import { Select } from "../../select";
|
||||
import type { IAsyncComputed } from "@ogre-tools/injectable-react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import upgradeChartTabStoreInjectable from "./store.injectable";
|
||||
import updateReleaseInjectable from "../../+helm-releases/update-release/update-release.injectable";
|
||||
import releasesInjectable from "../../+helm-releases/releases.injectable";
|
||||
import type { CallForHelmReleaseUpdate } from "../../+helm-releases/update-release/call-for-helm-release-update/call-for-helm-release-update.injectable";
|
||||
import { first } from "lodash/fp";
|
||||
import type { UpgradeChartModel } from "./upgrade-chart-model.injectable";
|
||||
import upgradeChartModelInjectable from "./upgrade-chart-model.injectable";
|
||||
import type { HelmChartVersion } from "../../+helm-charts/helm-charts/versions";
|
||||
|
||||
export interface UpgradeChartProps {
|
||||
className?: string;
|
||||
@@ -33,159 +26,74 @@ export interface UpgradeChartProps {
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
releases: IAsyncComputed<HelmRelease[]>;
|
||||
upgradeChartTabStore: UpgradeChartTabStore;
|
||||
updateRelease: CallForHelmReleaseUpdate;
|
||||
model: UpgradeChartModel;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps & Dependencies> {
|
||||
@observable error?: string;
|
||||
@observable versions = observable.array<ChartVersion>();
|
||||
@observable version: ChartVersion | undefined = undefined;
|
||||
|
||||
constructor(props: UpgradeChartProps & Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
disposeOnUnmount(this, [
|
||||
reaction(
|
||||
() => this.release,
|
||||
release => this.reloadVersions(release),
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
),
|
||||
reaction(
|
||||
() => this.release?.getRevision(),
|
||||
() => this.reloadValues(),
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
get tabId() {
|
||||
return this.props.tab.id;
|
||||
}
|
||||
|
||||
get release() {
|
||||
const tabData = this.props.upgradeChartTabStore.getData(this.tabId);
|
||||
|
||||
if (!tabData) return null;
|
||||
|
||||
return this.props.releases.value.get().find(release => release.getName() === tabData.releaseName);
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.props.upgradeChartTabStore.values.getData(this.tabId);
|
||||
}
|
||||
|
||||
async reloadValues() {
|
||||
this.props.upgradeChartTabStore.reloadValues(this.props.tab.id);
|
||||
}
|
||||
|
||||
async reloadVersions(release: HelmRelease | null | undefined) {
|
||||
if (!release) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.version = undefined;
|
||||
this.versions.clear();
|
||||
const versions = await helmChartStore.getVersions(release.getChart());
|
||||
|
||||
this.versions.replace(versions);
|
||||
this.version = first(this.versions);
|
||||
}
|
||||
|
||||
onChange = action((value: string) => {
|
||||
this.error = "";
|
||||
this.props.upgradeChartTabStore.values.setData(this.tabId, value);
|
||||
});
|
||||
|
||||
onError = action((error: Error | string) => {
|
||||
this.error = error.toString();
|
||||
});
|
||||
|
||||
upgrade = async () => {
|
||||
if (this.error || !this.release || !this.version || !this.value) {
|
||||
return null;
|
||||
const { model } = this.props;
|
||||
const { completedSuccessfully } = await model.submit();
|
||||
|
||||
if (completedSuccessfully) {
|
||||
return (
|
||||
<p>
|
||||
{"Release "}
|
||||
<b>{model.release.getName()}</b>
|
||||
{" successfully upgraded to version "}
|
||||
<b>{model.version.value.get()}</b>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
const { version, repo } = this.version;
|
||||
const releaseName = this.release.getName();
|
||||
const releaseNs = this.release.getNs();
|
||||
|
||||
await this.props.updateRelease(releaseName, releaseNs, {
|
||||
chart: this.release.getChart(),
|
||||
values: this.value,
|
||||
repo, version,
|
||||
});
|
||||
|
||||
return (
|
||||
<p>
|
||||
{"Release "}
|
||||
<b>{releaseName}</b>
|
||||
{" successfully upgraded to version "}
|
||||
<b>{version}</b>
|
||||
</p>
|
||||
);
|
||||
return null;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { tabId, release, value, error, onChange, onError, upgrade, versions, version } = this;
|
||||
const { className } = this.props;
|
||||
|
||||
if (!release || !this.props.upgradeChartTabStore.isReady(tabId) || !version) {
|
||||
return <Spinner center />;
|
||||
}
|
||||
const currentVersion = release.getVersion();
|
||||
const versionOptions = versions.map(version => ({
|
||||
value: version,
|
||||
label: `${version.repo}/${release.getChart()}-${version.version}`,
|
||||
}));
|
||||
const controlsAndInfo = (
|
||||
<div className="upgrade flex gaps align-center">
|
||||
<span>Release</span>
|
||||
{" "}
|
||||
<Badge label={release.getName()} />
|
||||
<span>Namespace</span>
|
||||
{" "}
|
||||
<Badge label={release.getNs()} />
|
||||
<span>Version</span>
|
||||
{" "}
|
||||
<Badge label={currentVersion} />
|
||||
<span>Upgrade version</span>
|
||||
<Select<ChartVersion, SelectOption<ChartVersion>, false>
|
||||
id="char-version-input"
|
||||
className="chart-version"
|
||||
menuPlacement="top"
|
||||
themeName="outlined"
|
||||
value={version}
|
||||
options={versionOptions}
|
||||
onChange={option => this.version = option?.value}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
const { model, className, tab } = this.props;
|
||||
const tabId = tab.id;
|
||||
const { release } = model;
|
||||
|
||||
return (
|
||||
<div className={cssNames("UpgradeChart flex column", className)}>
|
||||
<div
|
||||
className={cssNames("UpgradeChart flex column", className)}
|
||||
data-testid={`upgrade-chart-dock-tab-contents-for-${release.getId()}`}
|
||||
>
|
||||
<InfoPanel
|
||||
tabId={tabId}
|
||||
error={error}
|
||||
submit={upgrade}
|
||||
error={model.configration.error.get()}
|
||||
submit={this.upgrade}
|
||||
submitLabel="Upgrade"
|
||||
submittingMessage="Updating.."
|
||||
controls={controlsAndInfo}
|
||||
controls={(
|
||||
<div className="upgrade flex gaps align-center">
|
||||
<span>Release</span>
|
||||
{" "}
|
||||
<Badge label={release.getName()} />
|
||||
<span>Namespace</span>
|
||||
{" "}
|
||||
<Badge label={release.getNs()} />
|
||||
<span>Version</span>
|
||||
{" "}
|
||||
<Badge label={release.getVersion()} />
|
||||
<span>Upgrade version</span>
|
||||
<Select<HelmChartVersion, SelectOption<HelmChartVersion>, false>
|
||||
id="char-version-input"
|
||||
className="chart-version"
|
||||
menuPlacement="top"
|
||||
themeName="outlined"
|
||||
value={model.version.value.get()}
|
||||
options={model.versionOptions.get()}
|
||||
onChange={model.version.set}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<EditorPanel
|
||||
tabId={tabId}
|
||||
value={value ?? ""}
|
||||
onChange={onChange}
|
||||
onError={onError}
|
||||
value={model.configration.value.get()}
|
||||
onChange={model.configration.set}
|
||||
onError={model.configration.setError}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -193,10 +101,9 @@ export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps &
|
||||
}
|
||||
|
||||
export const UpgradeChart = withInjectables<Dependencies, UpgradeChartProps>(NonInjectedUpgradeChart, {
|
||||
getProps: (di, props) => ({
|
||||
releases: di.inject(releasesInjectable),
|
||||
updateRelease: di.inject(updateReleaseInjectable),
|
||||
upgradeChartTabStore: di.inject(upgradeChartTabStoreInjectable),
|
||||
getPlaceholder: () => <Spinner center />,
|
||||
getProps: async (di, props) => ({
|
||||
...props,
|
||||
model: await di.inject(upgradeChartModelInjectable, props.tab),
|
||||
}),
|
||||
});
|
||||
Reference in new issue
Block a user