1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Factor out uses of apiBase that cause test failures

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-07-18 11:34:40 -04:00
parent a51a4e75f2
commit 1cd9625faa
60 changed files with 811 additions and 717 deletions

View File

@ -19,6 +19,7 @@ import catalogGeneralEntityInjectable from "../catalog-entities/general-catalog-
import loggerInjectable from "../logger.injectable"; import loggerInjectable from "../logger.injectable";
import type { Logger } from "../logger"; import type { Logger } from "../logger";
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
import fsInjectable from "../fs/fs.injectable";
function getMockCatalogEntity(data: Partial<CatalogEntityData> & CatalogEntityKindData): CatalogEntity { function getMockCatalogEntity(data: Partial<CatalogEntityData> & CatalogEntityKindData): CatalogEntity {
return { return {
@ -46,7 +47,7 @@ describe("HotbarStore", () => {
beforeEach(async () => { beforeEach(async () => {
di = getDiForUnitTesting({ doGeneralOverrides: true }); di = getDiForUnitTesting({ doGeneralOverrides: true });
(di as any).unoverride(hotbarStoreInjectable); di.unoverride(hotbarStoreInjectable);
testCluster = getMockCatalogEntity({ testCluster = getMockCatalogEntity({
apiVersion: "v1", apiVersion: "v1",
@ -115,6 +116,7 @@ describe("HotbarStore", () => {
di.permitSideEffects(getConfigurationFileModelInjectable); di.permitSideEffects(getConfigurationFileModelInjectable);
di.permitSideEffects(appVersionInjectable); di.permitSideEffects(appVersionInjectable);
di.permitSideEffects(hotbarStoreInjectable); di.permitSideEffects(hotbarStoreInjectable);
di.permitSideEffects(fsInjectable);
}); });
afterEach(() => { afterEach(() => {

44
src/common/helm/chart.ts Normal file
View File

@ -0,0 +1,44 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export interface RawHelmChart {
apiVersion: string;
name: string;
version: string;
repo: string;
created: string;
digest?: string;
kubeVersion?: string;
description?: string;
home?: string;
engine?: string;
icon?: string;
appVersion?: string;
type?: string;
tillerVersion?: string;
deprecated?: boolean;
keywords?: string[];
sources?: string[];
urls?: string[];
maintainers?: HelmChartMaintainer[];
dependencies?: RawHelmChartDependency[];
annotations?: Record<string, string>;
}
export interface HelmChartMaintainer {
name: string;
email: string;
url?: string;
}
export interface RawHelmChartDependency {
name: string;
repository: string;
condition?: string;
version: string;
tags?: string[];
}
export type RepoHelmChartList = Record<string, RawHelmChart[]>;

View File

@ -4,7 +4,7 @@
*/ */
import { anyObject } from "jest-mock-extended"; import { anyObject } from "jest-mock-extended";
import { HelmChart } from "../endpoints/helm-charts.api"; import { HelmChart } from "../../../renderer/k8s/helm-chart";
describe("HelmChart tests", () => { describe("HelmChart tests", () => {
describe("HelmChart.create() tests", () => { describe("HelmChart.create() tests", () => {

View File

@ -1,227 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import yaml from "js-yaml";
import { formatDuration } from "../../utils";
import capitalize from "lodash/capitalize";
import { apiBase } from "../index";
import { helmChartStore } from "../../../renderer/components/+helm-charts/helm-chart.store";
import type { ItemObject } from "../../item.store";
import type { JsonApiData } from "../json-api";
import { buildURLPositional } from "../../utils/buildUrl";
import type { KubeJsonApiData } from "../kube-json-api";
export interface HelmReleaseDetails {
resources: KubeJsonApiData[];
name: string;
namespace: string;
version: string;
config: string; // release values
manifest: string;
info: {
deleted: string;
description: string;
first_deployed: string;
last_deployed: string;
notes: string;
status: string;
};
}
export interface HelmReleaseCreatePayload {
name?: string;
repo: string;
chart: string;
namespace: string;
version: string;
values: string;
}
export interface HelmReleaseUpdatePayload {
repo: string;
chart: string;
version: string;
values: string;
}
export interface HelmReleaseUpdateDetails {
log: string;
release: HelmReleaseDetails;
}
export interface HelmReleaseRevision {
revision: number;
updated: string;
status: string;
chart: string;
app_version: string;
description: string;
}
type EndpointParams = {}
| { namespace: string }
| { namespace: string; name: string }
| { namespace: string; name: string; route: string };
interface EndpointQuery {
all?: boolean;
}
const endpoint = buildURLPositional<EndpointParams, EndpointQuery>("/v2/releases/:namespace?/:name?/:route?");
export async function listReleases(namespace?: string): Promise<HelmRelease[]> {
const releases = await apiBase.get<HelmReleaseDto[]>(endpoint({ namespace }));
return releases.map(toHelmRelease);
}
export async function getRelease(name: string, namespace: string): Promise<HelmReleaseDetails> {
const path = endpoint({ name, namespace });
return apiBase.get(path);
}
export async function createRelease(payload: HelmReleaseCreatePayload): Promise<HelmReleaseUpdateDetails> {
const { repo, chart: rawChart, values: rawValues, ...data } = payload;
const chart = `${repo}/${rawChart}`;
const values = yaml.load(rawValues);
return apiBase.post(endpoint(), {
data: {
chart,
values,
...data,
},
});
}
export async function updateRelease(name: string, namespace: string, payload: HelmReleaseUpdatePayload): Promise<HelmReleaseUpdateDetails> {
const { repo, chart: rawChart, values: rawValues, ...data } = payload;
const chart = `${repo}/${rawChart}`;
const values = yaml.load(rawValues);
return apiBase.put(endpoint({ name, namespace }), {
data: {
chart,
values,
...data,
},
});
}
export async function deleteRelease(name: string, namespace: string): Promise<JsonApiData> {
const path = endpoint({ name, namespace });
return apiBase.del(path);
}
export async function getReleaseValues(name: string, namespace: string, all?: boolean): Promise<string> {
const route = "values";
const path = endpoint({ name, namespace, route }, { all });
return apiBase.get<string>(path);
}
export async function getReleaseHistory(name: string, namespace: string): Promise<HelmReleaseRevision[]> {
const route = "history";
const path = endpoint({ name, namespace, route });
return apiBase.get(path);
}
export async function rollbackRelease(name: string, namespace: string, revision: number): Promise<JsonApiData> {
const route = "rollback";
const path = endpoint({ name, namespace, route });
const data = { revision };
return apiBase.put(path, { data });
}
interface HelmReleaseDto {
appVersion: string;
name: string;
namespace: string;
chart: string;
status: string;
updated: string;
revision: string;
}
export interface HelmRelease extends HelmReleaseDto, ItemObject {
getNs: () => string;
getChart: (withVersion?: boolean) => string;
getRevision: () => number;
getStatus: () => string;
getVersion: () => string;
getUpdated: (humanize?: boolean, compact?: boolean) => string | number;
getRepo: () => Promise<string>;
}
const toHelmRelease = (release: HelmReleaseDto) : HelmRelease => ({
...release,
getId() {
return this.namespace + this.name;
},
getName() {
return this.name;
},
getNs() {
return this.namespace;
},
getChart(withVersion = false) {
let chart = this.chart;
if (!withVersion && this.getVersion() != "") {
const search = new RegExp(`-${this.getVersion()}`);
chart = chart.replace(search, "");
}
return chart;
},
getRevision() {
return parseInt(this.revision, 10);
},
getStatus() {
return capitalize(this.status);
},
getVersion() {
const versions = this.chart.match(/(?<=-)(v?\d+)[^-].*$/);
return versions?.[0] ?? "";
},
getUpdated(humanize = true, compact = true) {
const updated = this.updated.replace(/\s\w*$/, ""); // 2019-11-26 10:58:09 +0300 MSK -> 2019-11-26 10:58:09 +0300 to pass into Date()
const updatedDate = new Date(updated).getTime();
const diff = Date.now() - updatedDate;
if (humanize) {
return formatDuration(diff, compact);
}
return diff;
},
// Helm does not store from what repository the release is installed,
// so we have to try to guess it by searching charts
async getRepo() {
const chartName = this.getChart();
const version = this.getVersion();
const versions = await helmChartStore.getVersions(chartName);
const chartVersion = versions.find(
(chartVersion) => chartVersion.version === version,
);
return chartVersion ? chartVersion.repo : "";
},
});

View File

@ -1,28 +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";
const environmentVariablesInjectable = getInjectable({
id: "environment-variables",
instantiate: () => {
// IMPORTANT: The syntax needs to be exactly this in order to make environment variable values
// hard-coded at compile-time by Webpack.
const NODE_ENV = process.env.NODE_ENV;
return {
// Compile-time environment variables
NODE_ENV,
// Runtime environment variables
CICD: process.env.CICD,
LENS_DISABLE_GPU: process.env.LENS_DISABLE_GPU,
};
},
causesSideEffects: true,
});
export default environmentVariablesInjectable;

View File

@ -6,8 +6,8 @@
import type { SemVer } from "semver"; import type { SemVer } from "semver";
import semver, { coerce } from "semver"; import semver, { coerce } from "semver";
import * as iter from "./iter"; import * as iter from "./iter";
import type { RawHelmChart } from "../k8s-api/endpoints/helm-charts.api";
import logger from "../logger"; import logger from "../logger";
import type { RawHelmChart } from "../helm/chart";
export enum Ordering { export enum Ordering {
LESS = -1, LESS = -1,

View File

@ -0,0 +1,13 @@
/**
* 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";
const hardwareAccelerationShouldBeDisabledInjectable = getInjectable({
id: "hardware-acceleration-should-be-disabled",
instantiate: () => Boolean(process.env.LENS_DISABLE_GPU),
causesSideEffects: true,
});
export default hardwareAccelerationShouldBeDisabledInjectable;

View File

@ -7,7 +7,6 @@ import isProductionInjectable from "./is-production.injectable";
const isDevelopmentInjectable = getInjectable({ const isDevelopmentInjectable = getInjectable({
id: "is-development", id: "is-development",
instantiate: (di) => !di.inject(isProductionInjectable), instantiate: (di) => !di.inject(isProductionInjectable),
}); });

View File

@ -3,16 +3,11 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import environmentVariablesInjectable from "../utils/environment-variables.injectable";
const isProductionInjectable = getInjectable({ const isProductionInjectable = getInjectable({
id: "is-production", id: "is-production",
instantiate: () => process.env.NODE_ENV === "production",
instantiate: (di) => { causesSideEffects: true,
const { NODE_ENV: nodeEnv } = di.inject(environmentVariablesInjectable);
return nodeEnv === "production";
},
}); });
export default isProductionInjectable; export default isProductionInjectable;

View File

@ -3,16 +3,11 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import environmentVariablesInjectable from "../../../common/utils/environment-variables.injectable";
const directoryForIntegrationTestingInjectable = getInjectable({ const directoryForIntegrationTestingInjectable = getInjectable({
id: "directory-for-integration-testing", id: "directory-for-integration-testing",
instantiate: () => process.env.CICD,
instantiate: (di) => { causesSideEffects: true,
const environmentVariables = di.inject(environmentVariablesInjectable);
return environmentVariables.CICD;
},
}); });
export default directoryForIntegrationTestingInjectable; export default directoryForIntegrationTestingInjectable;

View File

@ -31,7 +31,6 @@ import hotbarStoreInjectable from "../common/hotbars/store.injectable";
import commandLineArgumentsInjectable from "./utils/command-line-arguments.injectable"; import commandLineArgumentsInjectable from "./utils/command-line-arguments.injectable";
import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.injectable"; import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.injectable";
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable"; import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
import environmentVariablesInjectable from "../common/utils/environment-variables.injectable";
import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable"; import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable"; import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable";
import setupSentryInjectable from "./start-main-application/runnables/setup-sentry.injectable"; import setupSentryInjectable from "./start-main-application/runnables/setup-sentry.injectable";
@ -39,7 +38,6 @@ import setupShellInjectable from "./start-main-application/runnables/setup-shell
import setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable"; import setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable";
import stopServicesAndExitAppInjectable from "./stop-services-and-exit-app.injectable"; import stopServicesAndExitAppInjectable from "./stop-services-and-exit-app.injectable";
import applicationMenuInjectable from "./menu/application-menu.injectable"; import applicationMenuInjectable from "./menu/application-menu.injectable";
import isDevelopmentInjectable from "../common/vars/is-development.injectable";
import setupSystemCaInjectable from "./start-main-application/runnables/setup-system-ca.injectable"; import setupSystemCaInjectable from "./start-main-application/runnables/setup-system-ca.injectable";
import setupDeepLinkingInjectable from "./electron-app/runnables/setup-deep-linking.injectable"; import setupDeepLinkingInjectable from "./electron-app/runnables/setup-deep-linking.injectable";
import exitAppInjectable from "./electron-app/features/exit-app.injectable"; import exitAppInjectable from "./electron-app/features/exit-app.injectable";
@ -99,6 +97,10 @@ import electronInjectable from "./utils/resolve-system-proxy/electron.injectable
import type { HotbarStore } from "../common/hotbars/store"; import type { HotbarStore } from "../common/hotbars/store";
import focusApplicationInjectable from "./electron-app/features/focus-application.injectable"; import focusApplicationInjectable from "./electron-app/features/focus-application.injectable";
import migrationLogInjectable from "./migrations/log.injectable"; import migrationLogInjectable from "./migrations/log.injectable";
import hardwareAccelerationShouldBeDisabledInjectable from "../common/vars/disable-gpu.injectable";
import directoryForIntegrationTestingInjectable from "./app-paths/directory-for-integration-testing/directory-for-integration-testing.injectable";
import isProductionInjectable from "../common/vars/is-production.injectable";
import isDebuggingInjectable from "../common/vars/is-debugging.injectable";
export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) { export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) {
const { const {
@ -141,8 +143,10 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
overrideRunnablesHavingSideEffects(di); overrideRunnablesHavingSideEffects(di);
overrideElectronFeatures(di); overrideElectronFeatures(di);
di.override(isDevelopmentInjectable, () => false); di.override(isProductionInjectable, () => true);
di.override(environmentVariablesInjectable, () => ({})); di.override(isDebuggingInjectable, () => false);
di.override(hardwareAccelerationShouldBeDisabledInjectable, () => false);
di.override(directoryForIntegrationTestingInjectable, () => undefined);
di.override(commandLineArgumentsInjectable, () => []); di.override(commandLineArgumentsInjectable, () => []);
di.override(productNameInjectable, () => "some-product-name"); di.override(productNameInjectable, () => "some-product-name");

View File

@ -6,12 +6,12 @@
import fs from "fs"; import fs from "fs";
import * as yaml from "js-yaml"; import * as yaml from "js-yaml";
import logger from "../logger"; import logger from "../logger";
import type { RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-charts.api";
import { iter, put, sortCharts } from "../../common/utils"; import { iter, put, sortCharts } from "../../common/utils";
import { execHelm } from "./exec"; import { execHelm } from "./exec";
import type { SetRequired } from "type-fest"; import type { SetRequired } from "type-fest";
import { assert } from "console"; import { assert } from "console";
import type { HelmRepo } from "../../common/helm/helm-repo"; import type { HelmRepo } from "../../common/helm/helm-repo";
import type { RepoHelmChartList } from "../../common/helm/chart";
interface ChartCacheEntry { interface ChartCacheEntry {
data: string; // serialized JSON data: string; // serialized JSON

View File

@ -3,7 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import environmentVariablesInjectable from "../../../common/utils/environment-variables.injectable"; import hardwareAccelerationShouldBeDisabledInjectable from "../../../common/vars/disable-gpu.injectable";
import disableHardwareAccelerationInjectable from "../../electron-app/features/disable-hardware-acceleration.injectable"; import disableHardwareAccelerationInjectable from "../../electron-app/features/disable-hardware-acceleration.injectable";
import { beforeElectronIsReadyInjectionToken } from "../runnable-tokens/before-electron-is-ready-injection-token"; import { beforeElectronIsReadyInjectionToken } from "../runnable-tokens/before-electron-is-ready-injection-token";
@ -11,12 +11,12 @@ const setupHardwareAccelerationInjectable = getInjectable({
id: "setup-hardware-acceleration", id: "setup-hardware-acceleration",
instantiate: (di) => { instantiate: (di) => {
const { LENS_DISABLE_GPU: hardwareAccelerationShouldBeDisabled } = di.inject(environmentVariablesInjectable); const disableGpuAcceleration = di.inject(hardwareAccelerationShouldBeDisabledInjectable);
const disableHardwareAcceleration = di.inject(disableHardwareAccelerationInjectable); const disableHardwareAcceleration = di.inject(disableHardwareAccelerationInjectable);
return { return {
run: () => { run: () => {
if (hardwareAccelerationShouldBeDisabled) { if (disableGpuAcceleration) {
disableHardwareAcceleration(); disableHardwareAcceleration();
} }
}, },

View File

@ -1,17 +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 type { GetChartDetailsOptions, IHelmChartDetails } from "../../../common/k8s-api/endpoints/helm-charts.api";
import { getChartDetails } from "../../../common/k8s-api/endpoints/helm-charts.api";
export type GetChartDetails = (repo: string, name: string, opts?: GetChartDetailsOptions) => Promise<IHelmChartDetails>;
const getChartDetailsInjectable = getInjectable({
id: "get-chart-details",
instantiate: (): GetChartDetails => getChartDetails,
causesSideEffects: true,
});
export default getChartDetailsInjectable;

View File

@ -6,7 +6,7 @@
import "./helm-chart-details.scss"; import "./helm-chart-details.scss";
import React, { Component } from "react"; import React, { Component } from "react";
import type { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api"; import type { HelmChart } from "../../k8s/helm-chart";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Drawer, DrawerItem } from "../drawer"; import { Drawer, DrawerItem } from "../drawer";
import { autoBind, stopPropagation } from "../../utils"; import { autoBind, stopPropagation } from "../../utils";

View File

@ -1,13 +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 { HelmChartStore } from "./helm-chart.store";
const helmChartStoreInjectable = getInjectable({
id: "helm-chart-store",
instantiate: () => new HelmChartStore(),
});
export default helmChartStoreInjectable;

View File

@ -7,8 +7,7 @@ import "./helm-charts.scss";
import React, { Component } from "react"; import React, { Component } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { helmChartStore } from "./helm-chart.store"; import type { HelmChart } from "../../k8s/helm-chart";
import type { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
import { HelmChartDetails } from "./helm-chart-details"; import { HelmChartDetails } from "./helm-chart-details";
import { ItemListLayout } from "../item-object-list/list-layout"; import { ItemListLayout } from "../item-object-list/list-layout";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";
@ -21,6 +20,8 @@ import navigateToHelmChartsInjectable from "../../../common/front-end-routing/ro
import { HelmChartIcon } from "./icon"; import { HelmChartIcon } from "./icon";
import helmChartsInjectable from "./helm-charts/helm-charts.injectable"; import helmChartsInjectable from "./helm-charts/helm-charts.injectable";
import selectedHelmChartInjectable from "./helm-charts/selected-helm-chart.injectable"; import selectedHelmChartInjectable from "./helm-charts/selected-helm-chart.injectable";
import type { HelmChartStore } from "./store";
import helmChartStoreInjectable from "./store.injectable";
enum columnId { enum columnId {
name = "name", name = "name",
@ -35,7 +36,7 @@ interface Dependencies {
chartName: IComputedValue<string>; chartName: IComputedValue<string>;
repo: IComputedValue<string>; repo: IComputedValue<string>;
}; };
helmChartStore: HelmChartStore;
navigateToHelmCharts: NavigateToHelmCharts; navigateToHelmCharts: NavigateToHelmCharts;
charts: IAsyncComputed<HelmChart[]>; charts: IAsyncComputed<HelmChart[]>;
@ -79,7 +80,7 @@ class NonInjectedHelmCharts extends Component<Dependencies> {
isConfigurable isConfigurable
tableId="helm_charts" tableId="helm_charts"
className="HelmCharts" className="HelmCharts"
store={helmChartStore} store={this.props.helmChartStore}
getItems={() => this.props.charts.value.get()} getItems={() => this.props.charts.value.get()}
isSelectable={false} isSelectable={false}
sortingCallbacks={{ sortingCallbacks={{
@ -132,16 +133,13 @@ class NonInjectedHelmCharts extends Component<Dependencies> {
} }
} }
export const HelmCharts = withInjectables<Dependencies>( export const HelmCharts = withInjectables<Dependencies>(NonInjectedHelmCharts, {
NonInjectedHelmCharts,
{
getProps: (di) => ({ getProps: (di) => ({
routeParameters: di.inject(helmChartsRouteParametersInjectable), routeParameters: di.inject(helmChartsRouteParametersInjectable),
navigateToHelmCharts: di.inject(navigateToHelmChartsInjectable), navigateToHelmCharts: di.inject(navigateToHelmChartsInjectable),
helmChartStore: di.inject(helmChartStoreInjectable),
charts: di.inject(helmChartsInjectable), charts: di.inject(helmChartsInjectable),
selectedChart: di.inject(selectedHelmChartInjectable), selectedChart: di.inject(selectedHelmChartInjectable),
}), }),
}, });
);

View File

@ -4,7 +4,7 @@
*/ */
import React, { useState } from "react"; import React, { useState } from "react";
import type { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api"; import type { HelmChart } from "../../k8s/helm-chart";
export interface HelmChartIconProps { export interface HelmChartIconProps {
className?: string; className?: string;

View File

@ -0,0 +1,19 @@
/**
* 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 getHelmChartDetailsInjectable from "../../k8s/helm-charts.api/get-details.injectable";
import listHelmChartsInjectable from "../../k8s/helm-charts.api/list.injectable";
import { HelmChartStore } from "./store";
const helmChartStoreInjectable = getInjectable({
id: "helm-chart-store",
instantiate: (di) => new HelmChartStore({
listHelmCharts: di.inject(listHelmChartsInjectable),
getHelmChartDetails: di.inject(getHelmChartDetailsInjectable),
}),
});
export default helmChartStoreInjectable;

View File

@ -6,20 +6,26 @@
import semver from "semver"; import semver from "semver";
import { observable, makeObservable } from "mobx"; import { observable, makeObservable } from "mobx";
import { autoBind, sortCompareChartVersions } from "../../utils"; import { autoBind, sortCompareChartVersions } from "../../utils";
import type { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api"; import type { HelmChart } from "../../k8s/helm-chart";
import { getChartDetails, listCharts } from "../../../common/k8s-api/endpoints/helm-charts.api";
import { ItemStore } from "../../../common/item.store"; import { ItemStore } from "../../../common/item.store";
import flatten from "lodash/flatten"; import flatten from "lodash/flatten";
import type { ListHelmCharts } from "../../k8s/helm-charts.api/list.injectable";
import type { GetHelmChartDetails } from "../../k8s/helm-charts.api/get-details.injectable";
export interface ChartVersion { export interface ChartVersion {
repo: string; repo: string;
version: string; version: string;
} }
export interface HelmChartStoreDependencies {
listHelmCharts: ListHelmCharts;
getHelmChartDetails: GetHelmChartDetails;
}
export class HelmChartStore extends ItemStore<HelmChart> { export class HelmChartStore extends ItemStore<HelmChart> {
@observable versions = observable.map<string, ChartVersion[]>(); @observable versions = observable.map<string, ChartVersion[]>();
constructor() { constructor(protected readonly dependencies: HelmChartStoreDependencies) {
super(); super();
makeObservable(this); makeObservable(this);
@ -28,7 +34,7 @@ export class HelmChartStore extends ItemStore<HelmChart> {
async loadAll() { async loadAll() {
try { try {
const res = await this.loadItems(() => listCharts()); const res = await this.loadItems(() => this.dependencies.listHelmCharts());
this.failedLoading = false; this.failedLoading = false;
@ -68,7 +74,7 @@ export class HelmChartStore extends ItemStore<HelmChart> {
} }
const loadVersions = async (repo: string) => { const loadVersions = async (repo: string) => {
const { versions } = await getChartDetails(repo, chartName); const { versions } = await this.dependencies.getHelmChartDetails(repo, chartName);
return versions.map(chart => ({ return versions.map(chart => ({
repo, repo,
@ -104,5 +110,3 @@ export class HelmChartStore extends ItemStore<HelmChart> {
throw new Error("removeItems is not supported"); throw new Error("removeItems is not supported");
} }
} }
export const helmChartStore = new HelmChartStore();

View File

@ -1,29 +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 type {
HelmReleaseCreatePayload } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import releasesInjectable from "../releases.injectable";
import callForCreateHelmReleaseInjectable from "./call-for-create-helm-release.injectable";
const createReleaseInjectable = getInjectable({
id: "create-release",
instantiate: (di) => {
const releases = di.inject(releasesInjectable);
const callForCreateRelease = di.inject(callForCreateHelmReleaseInjectable);
return async (payload: HelmReleaseCreatePayload) => {
const release = await callForCreateRelease(payload);
releases.invalidate();
return release;
};
},
});
export default createReleaseInjectable;

View File

@ -1,27 +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 type {
HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import {
deleteRelease,
} from "../../../../common/k8s-api/endpoints/helm-releases.api";
import releasesInjectable from "../releases.injectable";
const deleteReleaseInjectable = getInjectable({
id: "delete-release",
instantiate: (di) => {
const releases = di.inject(releasesInjectable);
return async (release: HelmRelease) => {
await deleteRelease(release.getName(), release.getNs());
releases.invalidate();
};
},
});
export default deleteReleaseInjectable;

View File

@ -12,21 +12,24 @@ import { observer } from "mobx-react";
import type { DialogProps } from "../../dialog"; import type { DialogProps } from "../../dialog";
import { Dialog } from "../../dialog"; import { Dialog } from "../../dialog";
import { Wizard, WizardStep } from "../../wizard"; import { Wizard, WizardStep } from "../../wizard";
import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import { getReleaseHistory, type HelmReleaseRevision } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import { Select } from "../../select"; import { Select } from "../../select";
import { Notifications } from "../../notifications"; import { Notifications } from "../../notifications";
import orderBy from "lodash/orderBy"; import orderBy from "lodash/orderBy";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import releaseRollbackDialogStateInjectable from "./state.injectable"; import releaseRollbackDialogStateInjectable from "./state.injectable";
import rollbackReleaseInjectable from "../rollback-release/rollback-release.injectable"; import type { HelmRelease } from "../../../k8s/helm-release";
import type { GetHelmReleaseHistory, HelmReleaseRevision } from "../../../k8s/helm-releases.api/get-history.injectable";
import type { RollbackHelmRelease } from "../../../k8s/helm-releases.api/rollback.injectable";
import rollbackHelmReleaseInjectable from "../../../k8s/helm-releases.api/rollback.injectable";
import getHelmReleaseHistoryInjectable from "../../../k8s/helm-releases.api/get-history.injectable";
export interface ReleaseRollbackDialogProps extends DialogProps { export interface ReleaseRollbackDialogProps extends DialogProps {
} }
interface Dependencies { interface Dependencies {
rollbackRelease: (releaseName: string, namespace: string, revisionNumber: number) => Promise<void>; rollbackHelmRelease: RollbackHelmRelease;
state: IObservableValue<HelmRelease | undefined>; state: IObservableValue<HelmRelease | undefined>;
getHelmReleaseHistory: GetHelmReleaseHistory;
} }
@observer @observer
@ -48,7 +51,7 @@ class NonInjectedReleaseRollbackDialog extends React.Component<ReleaseRollbackDi
onOpen = async (release: HelmRelease) => { onOpen = async (release: HelmRelease) => {
this.isLoading.set(true); this.isLoading.set(true);
const releases = await getReleaseHistory(release.getName(), release.getNs()); const releases = await this.props.getHelmReleaseHistory(release.getName(), release.getNs());
runInAction(() => { runInAction(() => {
this.revisions.replace(orderBy(releases, "revision", "desc")); this.revisions.replace(orderBy(releases, "revision", "desc"));
@ -65,7 +68,7 @@ class NonInjectedReleaseRollbackDialog extends React.Component<ReleaseRollbackDi
} }
try { try {
await this.props.rollbackRelease(release.getName(), release.getNs(), revision.revision); await this.props.rollbackHelmRelease(release.getName(), release.getNs(), revision.revision);
this.close(); this.close();
} catch (err) { } catch (err) {
Notifications.checkedError(err, "Unknown error occured while rolling back release"); Notifications.checkedError(err, "Unknown error occured while rolling back release");
@ -134,14 +137,11 @@ class NonInjectedReleaseRollbackDialog extends React.Component<ReleaseRollbackDi
} }
} }
export const ReleaseRollbackDialog = withInjectables<Dependencies, ReleaseRollbackDialogProps>( export const ReleaseRollbackDialog = withInjectables<Dependencies, ReleaseRollbackDialogProps>(NonInjectedReleaseRollbackDialog, {
NonInjectedReleaseRollbackDialog,
{
getProps: (di, props) => ({ getProps: (di, props) => ({
rollbackRelease: di.inject(rollbackReleaseInjectable),
state: di.inject(releaseRollbackDialogStateInjectable),
...props, ...props,
rollbackHelmRelease: di.inject(rollbackHelmReleaseInjectable),
state: di.inject(releaseRollbackDialogStateInjectable),
getHelmReleaseHistory: di.inject(getHelmReleaseHistoryInjectable),
}), }),
}, });
);

View File

@ -4,7 +4,7 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api"; import type { HelmRelease } from "../../../k8s/helm-release";
import releaseRollbackDialogStateInjectable from "./state.injectable"; import releaseRollbackDialogStateInjectable from "./state.injectable";
export type OpenHelmReleaseRollbackDialog = (release: HelmRelease) => void; export type OpenHelmReleaseRollbackDialog = (release: HelmRelease) => void;

View File

@ -4,7 +4,7 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { observable } from "mobx"; import { observable } from "mobx";
import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api"; import type { HelmRelease } from "../../../k8s/helm-release";
const releaseRollbackDialogStateInjectable = getInjectable({ const releaseRollbackDialogStateInjectable = getInjectable({
id: "release-rollback-dialog-state", id: "release-rollback-dialog-state",

View File

@ -3,21 +3,22 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { getRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import { asyncComputed } from "@ogre-tools/injectable-react"; import { asyncComputed } from "@ogre-tools/injectable-react";
import releaseInjectable from "./release.injectable"; import releaseInjectable from "./release.injectable";
import { waitUntilDefined } from "../../../utils"; import { waitUntilDefined } from "../../../utils";
import getHelmReleaseDetailsInjectable from "../../../k8s/helm-releases.api/get-details.injectable";
const releaseDetailsInjectable = getInjectable({ const releaseDetailsInjectable = getInjectable({
id: "release-details", id: "release-details",
instantiate: (di) => { instantiate: (di) => {
const releaseComputed = di.inject(releaseInjectable); const releaseComputed = di.inject(releaseInjectable);
const getHelmReleaseDetails = di.inject(getHelmReleaseDetailsInjectable);
return asyncComputed(async () => { return asyncComputed(async () => {
const release = await waitUntilDefined(releaseComputed); const release = await waitUntilDefined(releaseComputed);
return getRelease(release.name, release.namespace); return getHelmReleaseDetails(release.name, release.namespace);
});}, });},
}); });

View File

@ -11,7 +11,6 @@ import type { IComputedValue } from "mobx";
import { computed, makeObservable, observable } from "mobx"; import { computed, makeObservable, observable } from "mobx";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import kebabCase from "lodash/kebabCase"; import kebabCase from "lodash/kebabCase";
import type { HelmRelease, HelmReleaseDetails, HelmReleaseUpdateDetails, HelmReleaseUpdatePayload } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import { HelmReleaseMenu } from "../release-menu"; import { HelmReleaseMenu } from "../release-menu";
import { Drawer, DrawerItem, DrawerTitle } from "../../drawer"; import { Drawer, DrawerItem, DrawerTitle } from "../../drawer";
import { Badge } from "../../badge"; import { Badge } from "../../badge";
@ -29,7 +28,6 @@ import { MonacoEditor } from "../../monaco-editor";
import type { IAsyncComputed } from "@ogre-tools/injectable-react"; import type { IAsyncComputed } from "@ogre-tools/injectable-react";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import createUpgradeChartTabInjectable from "../../dock/upgrade-chart/create-upgrade-chart-tab.injectable"; import createUpgradeChartTabInjectable from "../../dock/upgrade-chart/create-upgrade-chart-tab.injectable";
import updateReleaseInjectable from "../update-release/update-release.injectable";
import releaseInjectable from "./release.injectable"; import releaseInjectable from "./release.injectable";
import releaseDetailsInjectable from "./release-details.injectable"; import releaseDetailsInjectable from "./release-details.injectable";
import releaseValuesInjectable from "./release-values.injectable"; import releaseValuesInjectable from "./release-values.injectable";
@ -41,16 +39,20 @@ import themeStoreInjectable from "../../../themes/store.injectable";
import type { GetDetailsUrl } from "../../kube-detail-params/get-details-url.injectable"; import type { GetDetailsUrl } from "../../kube-detail-params/get-details-url.injectable";
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable"; import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable"; import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable";
import type { HelmRelease } from "../../../k8s/helm-release";
import type { HelmReleaseDetails } from "../../../k8s/helm-releases.api";
import type { UpdateHelmRelease } from "../../../k8s/helm-releases.api/update.injectable";
import updateHelmReleaseInjectable from "../../../k8s/helm-releases.api/update.injectable";
export interface ReleaseDetailsProps { export interface ReleaseDetailsProps {
hideDetails(): void; hideDetails(): void;
} }
interface Dependencies { interface Dependencies {
release: IComputedValue<HelmRelease | null | undefined>; release: IComputedValue<HelmRelease | undefined>;
releaseDetails: IAsyncComputed<HelmReleaseDetails>; releaseDetails: IAsyncComputed<HelmReleaseDetails>;
releaseValues: IAsyncComputed<string>; releaseValues: IAsyncComputed<string>;
updateRelease: (name: string, namespace: string, payload: HelmReleaseUpdatePayload) => Promise<HelmReleaseUpdateDetails>; updateHelmRelease: UpdateHelmRelease;
createUpgradeChartTab: (release: HelmRelease) => void; createUpgradeChartTab: (release: HelmRelease) => void;
userSuppliedValuesAreShown: { toggle: () => void; value: boolean }; userSuppliedValuesAreShown: { toggle: () => void; value: boolean };
themeStore: ThemeStore; themeStore: ThemeStore;
@ -86,7 +88,7 @@ class NonInjectedReleaseDetails extends Component<ReleaseDetailsProps & Dependen
this.saving = true; this.saving = true;
try { try {
await this.props.updateRelease(name, namespace, data); await this.props.updateHelmRelease(name, namespace, data);
Notifications.ok( Notifications.ok(
<p> <p>
Release Release
@ -291,7 +293,7 @@ export const ReleaseDetails = withInjectables<Dependencies, ReleaseDetailsProps>
releaseDetails: di.inject(releaseDetailsInjectable), releaseDetails: di.inject(releaseDetailsInjectable),
releaseValues: di.inject(releaseValuesInjectable), releaseValues: di.inject(releaseValuesInjectable),
userSuppliedValuesAreShown: di.inject(userSuppliedValuesAreShownInjectable), userSuppliedValuesAreShown: di.inject(userSuppliedValuesAreShownInjectable),
updateRelease: di.inject(updateReleaseInjectable), updateHelmRelease: di.inject(updateHelmReleaseInjectable),
createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable), createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable),
themeStore: di.inject(themeStoreInjectable), themeStore: di.inject(themeStoreInjectable),
apiManager: di.inject(apiManagerInjectable), apiManager: di.inject(apiManagerInjectable),

View File

@ -3,17 +3,21 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { getReleaseValues } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import { asyncComputed } from "@ogre-tools/injectable-react"; import { asyncComputed } from "@ogre-tools/injectable-react";
import releaseInjectable from "./release.injectable"; import releaseInjectable from "./release.injectable";
import { Notifications } from "../../notifications";
import userSuppliedValuesAreShownInjectable from "./user-supplied-values-are-shown.injectable"; import userSuppliedValuesAreShownInjectable from "./user-supplied-values-are-shown.injectable";
import getHelmReleaseValuesInjectable from "../../../k8s/helm-releases.api/get-values.injectable";
import showErrorNotificationInjectable from "../../notifications/show-error-notification.injectable";
const releaseValuesInjectable = getInjectable({ const releaseValuesInjectable = getInjectable({
id: "release-values", id: "release-values",
instantiate: (di) => instantiate: (di) => {
asyncComputed(async () => { const getHelmReleaseValues = di.inject(getHelmReleaseValuesInjectable);
const showErrorNotification = di.inject(showErrorNotificationInjectable);
const userSuppliedValuesAreShown = di.inject(userSuppliedValuesAreShownInjectable);
return asyncComputed(async () => {
const release = di.inject(releaseInjectable).get(); const release = di.inject(releaseInjectable).get();
// TODO: Figure out way to get rid of defensive code // TODO: Figure out way to get rid of defensive code
@ -21,16 +25,15 @@ const releaseValuesInjectable = getInjectable({
return ""; return "";
} }
const userSuppliedValuesAreShown = di.inject(userSuppliedValuesAreShownInjectable).value;
try { try {
return await getReleaseValues(release.getName(), release.getNs(), !userSuppliedValuesAreShown) ?? ""; return await getHelmReleaseValues(release.getName(), release.getNs(), !userSuppliedValuesAreShown.value) ?? "";
} catch (error) { } catch (error) {
Notifications.error(`Failed to load values for ${release.getName()}: ${error}`); showErrorNotification(`Failed to load values for ${release.getName()}: ${error}`);
return ""; return "";
} }
}), });
},
}); });
export default releaseValuesInjectable; export default releaseValuesInjectable;

View File

@ -20,7 +20,7 @@ const releaseInjectable = getInjectable({
const namespace = routeParameters.namespace.get(); const namespace = routeParameters.namespace.get();
if (!name || !namespace) { if (!name || !namespace) {
return null; return undefined;
} }
return releases.value.get().find(matches({ name, namespace })); return releases.value.get().find(matches({ name, namespace }));

View File

@ -4,17 +4,19 @@
*/ */
import React from "react"; import React from "react";
import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api";
import { cssNames } from "../../utils"; import { cssNames } from "../../utils";
import type { MenuActionsProps } from "../menu/menu-actions"; import type { MenuActionsProps } from "../menu/menu-actions";
import { MenuActions } from "../menu/menu-actions"; import { MenuActions } from "../menu/menu-actions";
import { MenuItem } from "../menu"; import { MenuItem } from "../menu";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import type { CreateUpgradeChartTab } from "../dock/upgrade-chart/create-upgrade-chart-tab.injectable";
import createUpgradeChartTabInjectable from "../dock/upgrade-chart/create-upgrade-chart-tab.injectable"; import createUpgradeChartTabInjectable from "../dock/upgrade-chart/create-upgrade-chart-tab.injectable";
import deleteReleaseInjectable from "./delete-release/delete-release.injectable";
import type { OpenHelmReleaseRollbackDialog } from "./dialog/open.injectable"; import type { OpenHelmReleaseRollbackDialog } from "./dialog/open.injectable";
import openHelmReleaseRollbackDialogInjectable from "./dialog/open.injectable"; import openHelmReleaseRollbackDialogInjectable from "./dialog/open.injectable";
import type { HelmRelease } from "../../k8s/helm-release";
import type { DeleteHelmRelease } from "../../k8s/helm-releases.api/delete.injectable";
import deleteHelmReleaseInjectable from "../../k8s/helm-releases.api/delete.injectable";
export interface HelmReleaseMenuProps extends MenuActionsProps { export interface HelmReleaseMenuProps extends MenuActionsProps {
release: HelmRelease; release: HelmRelease;
@ -22,14 +24,16 @@ export interface HelmReleaseMenuProps extends MenuActionsProps {
} }
interface Dependencies { interface Dependencies {
deleteRelease: (release: HelmRelease) => Promise<any>; deleteHelmRelease: DeleteHelmRelease;
createUpgradeChartTab: (release: HelmRelease) => void; createUpgradeChartTab: CreateUpgradeChartTab;
openRollbackDialog: OpenHelmReleaseRollbackDialog; openRollbackDialog: OpenHelmReleaseRollbackDialog;
} }
class NonInjectedHelmReleaseMenu extends React.Component<HelmReleaseMenuProps & Dependencies> { class NonInjectedHelmReleaseMenu extends React.Component<HelmReleaseMenuProps & Dependencies> {
remove = () => { remove = async () => {
return this.props.deleteRelease(this.props.release); const { name, namespace } = this.props.release;
await this.props.deleteHelmRelease(name, namespace);
}; };
upgrade = () => { upgrade = () => {
@ -100,7 +104,7 @@ class NonInjectedHelmReleaseMenu extends React.Component<HelmReleaseMenuProps &
export const HelmReleaseMenu = withInjectables<Dependencies, HelmReleaseMenuProps>(NonInjectedHelmReleaseMenu, { export const HelmReleaseMenu = withInjectables<Dependencies, HelmReleaseMenuProps>(NonInjectedHelmReleaseMenu, {
getProps: (di, props) => ({ getProps: (di, props) => ({
...props, ...props,
deleteRelease: di.inject(deleteReleaseInjectable), deleteHelmRelease: di.inject(deleteHelmReleaseInjectable),
createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable), createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable),
openRollbackDialog: di.inject(openHelmReleaseRollbackDialogInjectable), openRollbackDialog: di.inject(openHelmReleaseRollbackDialogInjectable),
}), }),

View File

@ -5,8 +5,8 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { asyncComputed } from "@ogre-tools/injectable-react"; import { asyncComputed } from "@ogre-tools/injectable-react";
import namespaceStoreInjectable from "../+namespaces/store.injectable"; import namespaceStoreInjectable from "../+namespaces/store.injectable";
import { listReleases } from "../../../common/k8s-api/endpoints/helm-releases.api";
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable"; import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable";
import listHelmReleasesInjectable from "../../k8s/helm-releases.api/list.injectable";
import releaseSecretsInjectable from "./release-secrets.injectable"; import releaseSecretsInjectable from "./release-secrets.injectable";
const releasesInjectable = getInjectable({ const releasesInjectable = getInjectable({
@ -16,6 +16,7 @@ const releasesInjectable = getInjectable({
const clusterContext = di.inject(clusterFrameContextInjectable); const clusterContext = di.inject(clusterFrameContextInjectable);
const namespaceStore = di.inject(namespaceStoreInjectable); const namespaceStore = di.inject(namespaceStoreInjectable);
const releaseSecrets = di.inject(releaseSecretsInjectable); const releaseSecrets = di.inject(releaseSecretsInjectable);
const listHelmReleases = di.inject(listHelmReleasesInjectable);
return asyncComputed(async () => { return asyncComputed(async () => {
const contextNamespaces = namespaceStore.contextNamespaces || []; const contextNamespaces = namespaceStore.contextNamespaces || [];
@ -29,11 +30,10 @@ const releasesInjectable = getInjectable({
contextNamespaces.includes(namespace), contextNamespaces.includes(namespace),
); );
const releaseArrays = await (isLoadingAll ? listReleases() : Promise.all( const releaseArrays = await (isLoadingAll
contextNamespaces.map((namespace) => ? listHelmReleases()
listReleases(namespace), : Promise.all(contextNamespaces.map(listHelmReleases))
), );
));
return releaseArrays.flat(); return releaseArrays.flat();
}, []); }, []);

View File

@ -7,7 +7,6 @@ import "../item-object-list/item-list-layout.scss";
import "./releases.scss"; import "./releases.scss";
import React, { Component } from "react"; import React, { Component } from "react";
import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import namespaceStoreInjectable from "../+namespaces/store.injectable"; import namespaceStoreInjectable from "../+namespaces/store.injectable";
import type { ItemListStore } from "../item-object-list"; import type { ItemListStore } from "../item-object-list";
@ -17,14 +16,15 @@ import { kebabCase } from "lodash/fp";
import { HelmReleaseMenu } from "./release-menu"; import { HelmReleaseMenu } from "./release-menu";
import { ReleaseRollbackDialog } from "./dialog/dialog"; import { ReleaseRollbackDialog } from "./dialog/dialog";
import { ReleaseDetails } from "./release-details/release-details"; import { ReleaseDetails } from "./release-details/release-details";
import type { RemovableHelmRelease } from "./removable-releases.injectable";
import removableReleasesInjectable from "./removable-releases.injectable"; import removableReleasesInjectable from "./removable-releases.injectable";
import type { RemovableHelmRelease } from "./removable-releases";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";
import releasesInjectable from "./releases.injectable"; import releasesInjectable from "./releases.injectable";
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
import helmReleasesRouteParametersInjectable from "./helm-releases-route-parameters.injectable"; import helmReleasesRouteParametersInjectable from "./helm-releases-route-parameters.injectable";
import type { NavigateToHelmReleases } from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.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 navigateToHelmReleasesInjectable from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
import type { HelmRelease } from "../../k8s/helm-release";
enum columnId { enum columnId {
name = "name", name = "name",

View File

@ -3,20 +3,47 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { observable } from "mobx"; import { computed, observable } from "mobx";
import type { HelmRelease } from "../../k8s/helm-release";
import deleteHelmReleaseInjectable from "../../k8s/helm-releases.api/delete.injectable";
import { toggle } from "../../utils";
import releasesInjectable from "./releases.injectable"; import releasesInjectable from "./releases.injectable";
import deleteReleaseInjectable from "./delete-release/delete-release.injectable";
import { removableReleases } from "./removable-releases"; export interface RemovableHelmRelease extends HelmRelease {
toggle: () => void;
isSelected: boolean;
delete: () => Promise<void>;
}
const removableReleasesInjectable = getInjectable({ const removableReleasesInjectable = getInjectable({
id: "removable-releases", id: "removable-releases",
instantiate: (di) => instantiate: (di) => {
removableReleases({ const releases = di.inject(releasesInjectable);
releases: di.inject(releasesInjectable), const deleteHelmRelease = di.inject(deleteHelmReleaseInjectable);
deleteRelease: di.inject(deleteReleaseInjectable), const selectedReleaseIds = observable.set<string>();
releaseSelectionStatus: observable.map<string, boolean>(), const isSelected = (release: HelmRelease) => selectedReleaseIds.has(release.getId());
return computed(() =>
releases.value.get().map(
(release): RemovableHelmRelease => ({
...release,
toggle: () => {
toggle(selectedReleaseIds, release.getId());
},
get isSelected() {
return isSelected(release);
},
delete: async () => {
await deleteHelmRelease(release.name, release.namespace);
},
}), }),
),
);
},
}); });
export default removableReleasesInjectable; export default removableReleasesInjectable;

View File

@ -1,49 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { IAsyncComputed } from "@ogre-tools/injectable-react";
import type { ObservableMap } from "mobx";
import { computed } from "mobx";
import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api";
interface Dependencies {
releases: IAsyncComputed<HelmRelease[]>;
releaseSelectionStatus: ObservableMap<string, boolean>;
deleteRelease: (release: HelmRelease) => Promise<any>;
}
export interface RemovableHelmRelease extends HelmRelease {
toggle: () => void;
isSelected: boolean;
delete: () => Promise<void>;
}
export const removableReleases = ({
releases,
releaseSelectionStatus,
deleteRelease,
}: Dependencies) => {
const isSelected = (release: HelmRelease) =>
releaseSelectionStatus.get(release.getId()) || false;
return computed(() =>
releases.value.get().map(
(release): RemovableHelmRelease => ({
...release,
toggle: () => {
releaseSelectionStatus.set(release.getId(), !isSelected(release));
},
get isSelected() {
return isSelected(release);
},
delete: async () => {
await deleteRelease(release);
},
}),
),
);
};

View File

@ -1,23 +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 { rollbackRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import releasesInjectable from "../releases.injectable";
const rollbackReleaseInjectable = getInjectable({
id: "rollback-release",
instantiate: (di) => {
const releases = di.inject(releasesInjectable);
return async (name: string, namespace: string, revision: number) => {
await rollbackRelease(name, namespace, revision);
releases.invalidate();
};
},
});
export default rollbackReleaseInjectable;

View File

@ -1,34 +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 type {
HelmReleaseUpdatePayload } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import {
updateRelease,
} from "../../../../common/k8s-api/endpoints/helm-releases.api";
import releasesInjectable from "../releases.injectable";
const updateReleaseInjectable = getInjectable({
id: "update-release",
instantiate: (di) => {
const releases = di.inject(releasesInjectable);
return async (
name: string,
namespace: string,
payload: HelmReleaseUpdatePayload,
) => {
const result = await updateRelease(name, namespace, payload);
releases.invalidate();
return result;
};
},
});
export default updateReleaseInjectable;

View File

@ -4,7 +4,7 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import installChartTabStoreInjectable from "./store.injectable"; import installChartTabStoreInjectable from "./store.injectable";
import type { HelmChart } from "../../../../common/k8s-api/endpoints/helm-charts.api"; import type { HelmChart } from "../../../k8s/helm-chart";
import type { DockTab, DockTabCreateSpecific } from "../dock/store"; import type { DockTab, DockTabCreateSpecific } from "../dock/store";
import { TabKind } from "../dock/store"; import { TabKind } from "../dock/store";
import createDockTabInjectable from "../dock/create-dock-tab.injectable"; import createDockTabInjectable from "../dock/create-dock-tab.injectable";

View File

@ -8,7 +8,6 @@ import { waitUntilDefined } from "../../../../common/utils";
import type { CallForHelmChartValues } from "./chart-data/call-for-helm-chart-values.injectable"; import type { CallForHelmChartValues } from "./chart-data/call-for-helm-chart-values.injectable";
import callForHelmChartValuesInjectable 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 { IChartInstallData, InstallChartTabStore } from "./store";
import type { HelmChart } from "../../../../common/k8s-api/endpoints/helm-charts.api";
import React from "react"; import React from "react";
import { import {
action, action,
@ -19,13 +18,14 @@ import {
import assert from "assert"; import assert from "assert";
import type { CallForCreateHelmRelease } from "../../+helm-releases/create-release/call-for-create-helm-release.injectable"; 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 callForCreateHelmReleaseInjectable from "../../+helm-releases/create-release/call-for-create-helm-release.injectable";
import type { HelmReleaseUpdateDetails } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import dockStoreInjectable from "../dock/store.injectable"; import dockStoreInjectable from "../dock/store.injectable";
import type { NavigateToHelmReleases } from "../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.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 navigateToHelmReleasesInjectable from "../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
import type { SingleValue } from "react-select"; import type { SingleValue } from "react-select";
import type { CallForHelmChartVersions } from "../../+helm-charts/details/versions/call-for-helm-chart-versions.injectable"; 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 callForHelmChartVersionsInjectable from "../../+helm-charts/details/versions/call-for-helm-chart-versions.injectable";
import type { HelmChart } from "../../../k8s/helm-chart";
import type { HelmReleaseUpdateDetails } from "../../../k8s/helm-releases.api/update.injectable";
const installChartModelInjectable = getInjectable({ const installChartModelInjectable = getInjectable({
id: "install-chart-model", id: "install-chart-model",

View File

@ -5,8 +5,10 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { InstallChartTabStore } from "./store"; import { InstallChartTabStore } from "./store";
import createDockTabStoreInjectable from "../dock-tab-store/create-dock-tab-store.injectable"; import createDockTabStoreInjectable from "../dock-tab-store/create-dock-tab-store.injectable";
import type { HelmReleaseUpdateDetails } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import createStorageInjectable from "../../../utils/create-storage/create-storage.injectable"; import createStorageInjectable from "../../../utils/create-storage/create-storage.injectable";
import type { HelmReleaseUpdateDetails } from "../../../k8s/helm-releases.api/update.injectable";
import getHelmChartDetailsInjectable from "../../../k8s/helm-charts.api/get-details.injectable";
import getHelmChartValuesInjectable from "../../../k8s/helm-charts.api/get-values.injectable";
const installChartTabStoreInjectable = getInjectable({ const installChartTabStoreInjectable = getInjectable({
id: "install-chart-tab-store", id: "install-chart-tab-store",
@ -18,6 +20,8 @@ const installChartTabStoreInjectable = getInjectable({
createStorage: di.inject(createStorageInjectable), createStorage: di.inject(createStorageInjectable),
versionsStore: createDockTabStore<string[]>(), versionsStore: createDockTabStore<string[]>(),
detailsStore: createDockTabStore<HelmReleaseUpdateDetails>(), detailsStore: createDockTabStore<HelmReleaseUpdateDetails>(),
getHelmChartDetails: di.inject(getHelmChartDetailsInjectable),
getHelmChartValues: di.inject(getHelmChartValuesInjectable),
}); });
}, },
}); });

View File

@ -4,9 +4,9 @@
*/ */
import { makeObservable } from "mobx"; import { makeObservable } from "mobx";
import type { HelmReleaseUpdateDetails } from "../../../k8s/helm-releases.api/update.injectable";
import type { DockTabStoreDependencies } from "../dock-tab-store/dock-tab.store"; import type { DockTabStoreDependencies } from "../dock-tab-store/dock-tab.store";
import { DockTabStore } from "../dock-tab-store/dock-tab.store"; import { DockTabStore } from "../dock-tab-store/dock-tab.store";
import type { HelmReleaseUpdateDetails } from "../../../../common/k8s-api/endpoints/helm-releases.api";
export interface IChartInstallData { export interface IChartInstallData {
name: string; name: string;

View File

@ -5,18 +5,21 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import upgradeChartTabStoreInjectable from "./store.injectable"; import upgradeChartTabStoreInjectable from "./store.injectable";
import dockStoreInjectable from "../dock/store.injectable"; import dockStoreInjectable from "../dock/store.injectable";
import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api"; import type { DockTabCreateSpecific, TabId } from "../dock/store";
import type { DockStore, DockTabCreateSpecific, TabId } from "../dock/store";
import { TabKind } from "../dock/store"; import { TabKind } from "../dock/store";
import type { UpgradeChartTabStore } from "./store";
import { runInAction } from "mobx"; import { runInAction } from "mobx";
import type { HelmRelease } from "../../../k8s/helm-release";
interface Dependencies { export type CreateUpgradeChartTab = (release: HelmRelease, tabParams?: DockTabCreateSpecific) => TabId;
upgradeChartStore: UpgradeChartTabStore;
dockStore: DockStore;
}
const createUpgradeChartTab = ({ upgradeChartStore, dockStore }: Dependencies) => (release: HelmRelease, tabParams: DockTabCreateSpecific = {}): TabId => { const createUpgradeChartTabInjectable = getInjectable({
id: "create-upgrade-chart-tab",
instantiate: (di): CreateUpgradeChartTab => {
const dockStore = di.inject(dockStoreInjectable);
const upgradeChartStore = di.inject(upgradeChartTabStoreInjectable);
return (release, tabParams = {}) => {
const tabId = upgradeChartStore.getTabIdByRelease(release.getName()); const tabId = upgradeChartStore.getTabIdByRelease(release.getName());
if (tabId) { if (tabId) {
@ -43,15 +46,8 @@ const createUpgradeChartTab = ({ upgradeChartStore, dockStore }: Dependencies) =
return tab.id; return tab.id;
}); });
}; };
},
const createUpgradeChartTabInjectable = getInjectable({
id: "create-upgrade-chart-tab",
instantiate: (di) => createUpgradeChartTab({
upgradeChartStore: di.inject(upgradeChartTabStoreInjectable),
dockStore: di.inject(dockStoreInjectable),
}),
}); });
export default createUpgradeChartTabInjectable; export default createUpgradeChartTabInjectable;

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import { UpgradeChartTabStore } from "./store"; import { UpgradeChartTabStore } from "./store";
import createDockTabStoreInjectable from "../dock-tab-store/create-dock-tab-store.injectable"; import createDockTabStoreInjectable from "../dock-tab-store/create-dock-tab-store.injectable";
import createStorageInjectable from "../../../utils/create-storage/create-storage.injectable"; import createStorageInjectable from "../../../utils/create-storage/create-storage.injectable";
import getHelmReleaseValuesInjectable from "../../../k8s/helm-releases.api/get-values.injectable";
const upgradeChartTabStoreInjectable = getInjectable({ const upgradeChartTabStoreInjectable = getInjectable({
id: "upgrade-chart-tab-store", id: "upgrade-chart-tab-store",
@ -16,6 +17,7 @@ const upgradeChartTabStoreInjectable = getInjectable({
return new UpgradeChartTabStore({ return new UpgradeChartTabStore({
createStorage: di.inject(createStorageInjectable), createStorage: di.inject(createStorageInjectable),
valuesStore: createDockTabStore<string>(), valuesStore: createDockTabStore<string>(),
getHelmReleaseValues: di.inject(getHelmReleaseValuesInjectable),
}); });
}, },
}); });

View File

@ -7,8 +7,8 @@ import { action, computed, makeObservable } from "mobx";
import type { TabId } from "../dock/store"; import type { TabId } from "../dock/store";
import type { DockTabStoreDependencies } from "../dock-tab-store/dock-tab.store"; import type { DockTabStoreDependencies } from "../dock-tab-store/dock-tab.store";
import { DockTabStore } 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"; import assert from "assert";
import type { GetHelmReleaseValues } from "../../../k8s/helm-releases.api/get-values.injectable";
export interface IChartUpgradeData { export interface IChartUpgradeData {
releaseName: string; releaseName: string;
@ -17,6 +17,7 @@ export interface IChartUpgradeData {
export interface UpgradeChartTabStoreDependencies extends DockTabStoreDependencies { export interface UpgradeChartTabStoreDependencies extends DockTabStoreDependencies {
valuesStore: DockTabStore<string>; valuesStore: DockTabStore<string>;
getHelmReleaseValues: GetHelmReleaseValues;
} }
export class UpgradeChartTabStore extends DockTabStore<IChartUpgradeData> { export class UpgradeChartTabStore extends DockTabStore<IChartUpgradeData> {
@ -44,7 +45,7 @@ export class UpgradeChartTabStore extends DockTabStore<IChartUpgradeData> {
assert(data, "cannot reload values if no data"); assert(data, "cannot reload values if no data");
const { releaseName, releaseNamespace } = data; const { releaseName, releaseNamespace } = data;
const values = await getReleaseValues(releaseName, releaseNamespace, true); const values = await this.dependencies.getHelmReleaseValues(releaseName, releaseNamespace, true);
this.values.setData(tabId, values); this.values.setData(tabId, values);
} }

View File

@ -15,15 +15,17 @@ import type { UpgradeChartTabStore } from "./store";
import { Spinner } from "../../spinner"; import { Spinner } from "../../spinner";
import { Badge } from "../../badge"; import { Badge } from "../../badge";
import { EditorPanel } from "../editor-panel"; import { EditorPanel } from "../editor-panel";
import { helmChartStore, type ChartVersion } from "../../+helm-charts/helm-chart.store"; import type { ChartVersion, HelmChartStore } from "../../+helm-charts/store";
import type { HelmRelease, HelmReleaseUpdateDetails, HelmReleaseUpdatePayload } from "../../../../common/k8s-api/endpoints/helm-releases.api";
import type { SelectOption } from "../../select"; import type { SelectOption } from "../../select";
import { Select } from "../../select"; import { Select } from "../../select";
import type { IAsyncComputed } from "@ogre-tools/injectable-react"; import type { IAsyncComputed } from "@ogre-tools/injectable-react";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import upgradeChartTabStoreInjectable from "./store.injectable"; import upgradeChartTabStoreInjectable from "./store.injectable";
import updateReleaseInjectable from "../../+helm-releases/update-release/update-release.injectable";
import releasesInjectable from "../../+helm-releases/releases.injectable"; import releasesInjectable from "../../+helm-releases/releases.injectable";
import helmChartStoreInjectable from "../../+helm-charts/store.injectable";
import type { HelmRelease } from "../../../k8s/helm-release";
import type { UpdateHelmRelease } from "../../../k8s/helm-releases.api/update.injectable";
import updateHelmReleaseInjectable from "../../../k8s/helm-releases.api/update.injectable";
export interface UpgradeChartProps { export interface UpgradeChartProps {
className?: string; className?: string;
@ -33,7 +35,8 @@ export interface UpgradeChartProps {
interface Dependencies { interface Dependencies {
releases: IAsyncComputed<HelmRelease[]>; releases: IAsyncComputed<HelmRelease[]>;
upgradeChartTabStore: UpgradeChartTabStore; upgradeChartTabStore: UpgradeChartTabStore;
updateRelease: (name: string, namespace: string, payload: HelmReleaseUpdatePayload) => Promise<HelmReleaseUpdateDetails>; updateHelmRelease: UpdateHelmRelease;
helmChartStore: HelmChartStore;
} }
@observer @observer
@ -93,7 +96,7 @@ export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps &
this.version = undefined; this.version = undefined;
this.versions.clear(); this.versions.clear();
const versions = await helmChartStore.getVersions(release.getChart()); const versions = await this.props.helmChartStore.getVersions(release.getChart());
this.versions.replace(versions); this.versions.replace(versions);
this.version = this.versions[0]; this.version = this.versions[0];
@ -117,7 +120,7 @@ export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps &
const releaseName = this.release.getName(); const releaseName = this.release.getName();
const releaseNs = this.release.getNs(); const releaseNs = this.release.getNs();
await this.props.updateRelease(releaseName, releaseNs, { await this.props.updateHelmRelease(releaseName, releaseNs, {
chart: this.release.getChart(), chart: this.release.getChart(),
values: this.value, values: this.value,
repo, version, repo, version,
@ -192,9 +195,10 @@ export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps &
export const UpgradeChart = withInjectables<Dependencies, UpgradeChartProps>(NonInjectedUpgradeChart, { export const UpgradeChart = withInjectables<Dependencies, UpgradeChartProps>(NonInjectedUpgradeChart, {
getProps: (di, props) => ({ getProps: (di, props) => ({
releases: di.inject(releasesInjectable),
updateRelease: di.inject(updateReleaseInjectable),
upgradeChartTabStore: di.inject(upgradeChartTabStoreInjectable),
...props, ...props,
releases: di.inject(releasesInjectable),
updateHelmRelease: di.inject(updateHelmReleaseInjectable),
upgradeChartTabStore: di.inject(upgradeChartTabStoreInjectable),
helmChartStore: di.inject(helmChartStoreInjectable),
}), }),
}); });

View File

@ -73,6 +73,8 @@ import forceUpdateModalRootFrameComponentInjectable from "./application-update/f
import legacyOnChannelListenInjectable from "./ipc/legacy-channel-listen.injectable"; import legacyOnChannelListenInjectable from "./ipc/legacy-channel-listen.injectable";
import getEntitySettingCommandsInjectable from "./components/command-palette/registered-commands/get-entity-setting-commands.injectable"; import getEntitySettingCommandsInjectable from "./components/command-palette/registered-commands/get-entity-setting-commands.injectable";
import storageSaveDelayInjectable from "./utils/create-storage/storage-save-delay.injectable"; import storageSaveDelayInjectable from "./utils/create-storage/storage-save-delay.injectable";
import isProductionInjectable from "../common/vars/is-production.injectable";
import isDebuggingInjectable from "../common/vars/is-debugging.injectable";
export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {}) => { export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {}) => {
const { const {
@ -208,6 +210,8 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
overrideFsWithFakes(di); overrideFsWithFakes(di);
di.override(focusWindowInjectable, () => () => {}); di.override(focusWindowInjectable, () => () => {});
di.override(isProductionInjectable, () => true);
di.override(isDebuggingInjectable, () => false);
di.override(loggerInjectable, () => ({ di.override(loggerInjectable, () => ({
warn: noop, warn: noop,

View File

@ -3,95 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { compile } from "path-to-regexp";
import { apiBase } from "../index";
import { stringify } from "querystring";
import type { RequestInit } from "node-fetch";
import { autoBind, bifurcateArray, isDefined } from "../../utils";
import Joi from "joi"; import Joi from "joi";
import type { HelmChartMaintainer, RawHelmChart, RawHelmChartDependency } from "../../common/helm/chart";
export type RepoHelmChartList = Record<string, RawHelmChart[]>; import { autoBind, bifurcateArray } from "../utils";
export interface IHelmChartDetails {
readme: string;
versions: HelmChart[];
}
const endpoint = compile(`/v2/charts/:repo?/:name?`) as (params?: {
repo?: string;
name?: string;
}) => string;
/**
* Get a list of all helm charts from all saved helm repos
*/
export async function listCharts(): Promise<HelmChart[]> {
const data = await apiBase.get<Record<string, RepoHelmChartList>>(endpoint());
return Object
.values(data)
.reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), new Array<RawHelmChart[]>())
.map(([chart]) => HelmChart.create(chart, { onError: "log" }))
.filter(isDefined);
}
export interface GetChartDetailsOptions {
version?: string;
reqInit?: RequestInit;
}
/**
* Get the readme and all versions of a chart
* @param repo The repo to get from
* @param name The name of the chart to request the data of
* @param options.version The version of the chart's readme to get, default latest
* @param options.reqInit A way for passing in an abort controller or other browser request options
*/
export async function getChartDetails(repo: string, name: string, { version, reqInit }: GetChartDetailsOptions = {}): Promise<IHelmChartDetails> {
const path = endpoint({ repo, name });
const { readme, ...data } = await apiBase.get<IHelmChartDetails>(`${path}?${stringify({ version })}`, undefined, reqInit);
const versions = data.versions.map(version => HelmChart.create(version, { onError: "log" })).filter(isDefined);
return {
readme,
versions,
};
}
/**
* Get chart values related to a specific repos' version of a chart
* @param repo The repo to get from
* @param name The name of the chart to request the data of
* @param version The version to get the values from
*/
export async function getChartValues(repo: string, name: string, version: string): Promise<string> {
return apiBase.get<string>(`/v2/charts/${repo}/${name}/values?${stringify({ version })}`);
}
export interface RawHelmChart {
apiVersion: string;
name: string;
version: string;
repo: string;
created: string;
digest?: string;
kubeVersion?: string;
description?: string;
home?: string;
engine?: string;
icon?: string;
appVersion?: string;
type?: string;
tillerVersion?: string;
deprecated?: boolean;
keywords?: string[];
sources?: string[];
urls?: string[];
maintainers?: HelmChartMaintainer[];
dependencies?: RawHelmChartDependency[];
annotations?: Record<string, string>;
}
const helmChartMaintainerValidator = Joi.object<HelmChartMaintainer>({ const helmChartMaintainerValidator = Joi.object<HelmChartMaintainer>({
name: Joi name: Joi
@ -225,20 +139,6 @@ export interface HelmChartCreateOpts {
onError?: "throw" | "log"; onError?: "throw" | "log";
} }
export interface HelmChartMaintainer {
name: string;
email: string;
url?: string;
}
export interface RawHelmChartDependency {
name: string;
repository: string;
condition?: string;
version: string;
tags?: string[];
}
export type HelmChartDependency = Required<Omit<RawHelmChartDependency, "condition">> export type HelmChartDependency = Required<Omit<RawHelmChartDependency, "condition">>
& Pick<RawHelmChartDependency, "condition">; & Pick<RawHelmChartDependency, "condition">;

View File

@ -0,0 +1,50 @@
/**
* 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 { isDefined } from "../../../common/utils";
import { stringify } from "querystring";
import type { RequestInit } from "node-fetch";
import { HelmChart } from "../helm-chart";
import apiBaseInjectable from "../api-base.injectable";
export interface HelmChartDetails {
readme: string;
versions: HelmChart[];
}
export interface GetChartDetailsOptions {
version?: string;
reqInit?: RequestInit;
}
/**
* Get the readme and all versions of a chart
* @param repo The repo to get from
* @param name The name of the chart to request the data of
* @param options.version The version of the chart's readme to get, default latest
* @param options.reqInit A way for passing in an abort controller or other browser request options
*/
export type GetHelmChartDetails = (repo: string, name: string, opts?: GetChartDetailsOptions) => Promise<HelmChartDetails>;
const getHelmChartDetailsInjectable = getInjectable({
id: "get-helm-chart-details",
instantiate: (di): GetHelmChartDetails => {
const apiBase = di.inject(apiBaseInjectable);
return async (repo, name, { version, reqInit } = {}) => {
const { readme, versions: rawVersions } = await apiBase.get(`/v2/charts/${repo}/${name}?${stringify({ version })}`, undefined, reqInit) as HelmChartDetails;
const versions = rawVersions
.map(version => HelmChart.create(version, { onError: "log" }))
.filter(isDefined);
return {
readme,
versions,
};
};
},
});
export default getHelmChartDetailsInjectable;

View File

@ -0,0 +1,26 @@
/**
* 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 { stringify } from "querystring";
import apiBaseInjectable from "../api-base.injectable";
/**
* Get chart values related to a specific repos' version of a chart
* @param repo The repo to get from
* @param name The name of the chart to request the data of
* @param version The version to get the values from
*/
export type GetHelmChartValues = (repo: string, name: string, version: string) => Promise<string>;
const getHelmChartValuesInjectable = getInjectable({
id: "get-helm-chart-values",
instantiate: (di): GetHelmChartValues => {
const apiBase = di.inject(apiBaseInjectable);
return (repo, name, version) => apiBase.get(`/v2/charts/${repo}/${name}/values?${stringify({ version })}`);
},
});
export default getHelmChartValuesInjectable;

View File

@ -0,0 +1,33 @@
/**
* 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 type { RawHelmChart, RepoHelmChartList } from "../../../common/helm/chart";
import { isDefined } from "../../../common/utils";
import apiBaseInjectable from "../api-base.injectable";
import { HelmChart } from "../helm-chart";
/**
* Get a list of all helm charts from all saved helm repos
*/
export type ListHelmCharts = () => Promise<HelmChart[]>;
const listHelmChartsInjectable = getInjectable({
id: "list-helm-charts",
instantiate: (di): ListHelmCharts => {
const apiBase = di.inject(apiBaseInjectable);
return async () => {
const data = await apiBase.get<Record<string, RepoHelmChartList>>("/v2/charts");
return Object
.values(data)
.reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), new Array<RawHelmChart[]>())
.map(([chart]) => HelmChart.create(chart, { onError: "log" }))
.filter(isDefined);
};
},
});
export default listHelmChartsInjectable;

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { ItemObject } from "../../common/item.store";
export interface RawHelmRelease {
appVersion: string;
name: string;
namespace: string;
chart: string;
status: string;
updated: string;
revision: string;
}
export interface HelmRelease extends RawHelmRelease, ItemObject {
getNs: () => string;
getChart: (withVersion?: boolean) => string;
getRevision: () => number;
getStatus: () => string;
getVersion: () => string;
getUpdated: (humanize?: boolean, compact?: boolean) => string | number;
getRepo: () => Promise<string>;
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { KubeJsonApiData } from "../../common/k8s-api/kube-json-api";
import { buildURLPositional } from "../../common/utils/buildUrl";
export interface HelmReleaseDetails {
resources: KubeJsonApiData[];
name: string;
namespace: string;
version: string;
config: string; // release values
manifest: string;
info: {
deleted: string;
description: string;
first_deployed: string;
last_deployed: string;
notes: string;
status: string;
};
}
type EndpointParams = {}
| { namespace: string }
| { namespace: string; name: string };
export const helmReleasesUrl = buildURLPositional<EndpointParams>("/v2/releases/:namespace?/:name?");

View File

@ -0,0 +1,49 @@
/**
* 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 { load } from "js-yaml";
import releasesInjectable from "../../components/+helm-releases/releases.injectable";
import apiBaseInjectable from "../api-base.injectable";
import type { HelmReleaseDetails } from "../helm-releases.api";
import { helmReleasesUrl } from "../helm-releases.api";
export interface HelmReleaseCreateDetails {
log: string;
release: HelmReleaseDetails;
}
export interface HelmReleaseCreatePayload {
name?: string;
repo: string;
chart: string;
namespace: string;
version: string;
values: string;
}
export type CreateHelmRelease = (payload: HelmReleaseCreatePayload) => Promise<HelmReleaseCreateDetails>;
const createHelmReleaseInjectable = getInjectable({
id: "create-helm-release",
instantiate: (di): CreateHelmRelease => {
const apiBase = di.inject(apiBaseInjectable);
const releases = di.inject(releasesInjectable);
return async ({ repo, chart, values, ...data }) => {
const result = await apiBase.post(helmReleasesUrl(), {
data: {
chart: `${repo}/${chart}`,
values: load(values),
...data,
},
}) as HelmReleaseCreateDetails;
releases.invalidate();
return result;
};
},
});
export default createHelmReleaseInjectable;

View File

@ -0,0 +1,29 @@
/**
* 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 type { JsonApiData } from "../../../common/k8s-api/json-api";
import releasesInjectable from "../../components/+helm-releases/releases.injectable";
import apiBaseInjectable from "../api-base.injectable";
import { helmReleasesUrl } from "../helm-releases.api";
export type DeleteHelmRelease = (name: string, namespace: string) => Promise<JsonApiData>;
const deleteHelmReleaseInjectable = getInjectable({
id: "delete-helm-release",
instantiate: (di): DeleteHelmRelease => {
const apiBase = di.inject(apiBaseInjectable);
const releases = di.inject(releasesInjectable);
return async (name, namespace) => {
const result = await apiBase.del(helmReleasesUrl({ name, namespace }));
releases.invalidate();
return result;
};
},
});
export default deleteHelmReleaseInjectable;

View File

@ -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 } from "@ogre-tools/injectable";
import apiBaseInjectable from "../api-base.injectable";
import type { HelmReleaseDetails } from "../helm-releases.api";
import { helmReleasesUrl } from "../helm-releases.api";
export type GetHelmReleaseDetails = (name: string, namespace: string) => Promise<HelmReleaseDetails>;
const getHelmReleaseDetailsInjectable = getInjectable({
id: "get-helm-release-details",
instantiate: (di): GetHelmReleaseDetails => {
const apiBase = di.inject(apiBaseInjectable);
return (name, namespace) => apiBase.get(helmReleasesUrl({ name, namespace }));
},
});
export default getHelmReleaseDetailsInjectable;

View File

@ -0,0 +1,31 @@
/**
* 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 { buildURLPositional } from "../../../common/utils/buildUrl";
import apiBaseInjectable from "../api-base.injectable";
export interface HelmReleaseRevision {
revision: number;
updated: string;
status: string;
chart: string;
app_version: string;
description: string;
}
export type GetHelmReleaseHistory = (name: string, namespace: string) => Promise<HelmReleaseRevision[]>;
const getHelmReleaseHistoryUrl = buildURLPositional<{ namespace: string; name: string }>("/v2/releases/:namespace/:name/history");
const getHelmReleaseHistoryInjectable = getInjectable({
id: "get-helm-release-history",
instantiate: (di): GetHelmReleaseHistory => {
const apiBase = di.inject(apiBaseInjectable);
return (name, namespace) => apiBase.get(getHelmReleaseHistoryUrl({ name, namespace }));
},
});
export default getHelmReleaseHistoryInjectable;

View File

@ -0,0 +1,28 @@
/**
* 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 { buildURLPositional } from "../../../common/utils/buildUrl";
import apiBaseInjectable from "../api-base.injectable";
export type GetHelmReleaseValues = (name: string, namespace: string, all?: boolean) => Promise<string>;
const getHelmReleaseValuesUrl = buildURLPositional<
{ namespace: string; name: string },
{ all?: boolean }
>("/v2/releases/:namespace/:name/values");
const getHelmReleaseValuesInjectable = getInjectable({
id: "get-helm-release-values",
instantiate: (di): GetHelmReleaseValues => {
const apiBase = di.inject(apiBaseInjectable);
return (name, namespace, all) => apiBase.get(getHelmReleaseValuesUrl(
{ name, namespace },
{ all },
));
},
});
export default getHelmReleaseValuesInjectable;

View File

@ -0,0 +1,27 @@
/**
* 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 apiBaseInjectable from "../api-base.injectable";
import type { HelmRelease, RawHelmRelease } from "../helm-release";
import { helmReleasesUrl } from "../helm-releases.api";
import toHelmReleaseInjectable from "./to-instance.injectable";
export type ListHelmReleases = (namespace?: string) => Promise<HelmRelease[]>;
const listHelmReleasesInjectable = getInjectable({
id: "list-helm-releases",
instantiate: (di): ListHelmReleases => {
const apiBase = di.inject(apiBaseInjectable);
const toHelmRelease = di.inject(toHelmReleaseInjectable);
return async (namespace) => {
const releases = await apiBase.get<RawHelmRelease[]>(helmReleasesUrl({ namespace }));
return releases.map(toHelmRelease);
};
},
});
export default listHelmReleasesInjectable;

View File

@ -0,0 +1,34 @@
/**
* 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 type { JsonApiData } from "../../../common/k8s-api/json-api";
import { buildURLPositional } from "../../../common/utils/buildUrl";
import releasesInjectable from "../../components/+helm-releases/releases.injectable";
import apiBaseInjectable from "../api-base.injectable";
export type RollbackHelmRelease = (name: string, namespace: string, revision: number) => Promise<JsonApiData>;
const rollbackHelmReleaseUrl = buildURLPositional<{ namespace: string; name: string }>("/v2/releases/:namespace/:name/rollback");
const rollbackHelmReleaseInjectable = getInjectable({
id: "rollback-helm-release",
instantiate: (di): RollbackHelmRelease => {
const apiBase = di.inject(apiBaseInjectable);
const releases = di.inject(releasesInjectable);
return async (name, namespace, revision) => {
const result = await apiBase.put(
rollbackHelmReleaseUrl({ name, namespace }),
{ data: { revision }},
);
releases.invalidate();
return result;
};
},
});
export default rollbackHelmReleaseInjectable;

View File

@ -0,0 +1,87 @@
/**
* 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 { capitalize } from "lodash/fp";
import helmChartStoreInjectable from "../../components/+helm-charts/store.injectable";
import { formatDuration } from "../../utils";
import type { HelmRelease, RawHelmRelease } from "../helm-release";
export type ToHelmRelease = (raw: RawHelmRelease) => HelmRelease;
const toHelmReleaseInjectable = getInjectable({
id: "to-helm-release",
instantiate: (di): ToHelmRelease => {
const helmChartStore = di.inject(helmChartStoreInjectable);
return (release) => ({
...release,
getId() {
return this.namespace + this.name;
},
getName() {
return this.name;
},
getNs() {
return this.namespace;
},
getChart(withVersion = false) {
let chart = this.chart;
if (!withVersion && this.getVersion() != "") {
const search = new RegExp(`-${this.getVersion()}`);
chart = chart.replace(search, "");
}
return chart;
},
getRevision() {
return parseInt(this.revision, 10);
},
getStatus() {
return capitalize(this.status);
},
getVersion() {
const versions = this.chart.match(/(?<=-)(v?\d+)[^-].*$/);
return versions?.[0] ?? "";
},
getUpdated(humanize = true, compact = true) {
const updated = this.updated.replace(/\s\w*$/, ""); // 2019-11-26 10:58:09 +0300 MSK -> 2019-11-26 10:58:09 +0300 to pass into Date()
const updatedDate = new Date(updated).getTime();
const diff = Date.now() - updatedDate;
if (humanize) {
return formatDuration(diff, compact);
}
return diff;
},
// Helm does not store from what repository the release is installed,
// so we have to try to guess it by searching charts
async getRepo() {
const chartName = this.getChart();
const version = this.getVersion();
const versions = await helmChartStore.getVersions(chartName);
const chartVersion = versions.find(
(chartVersion) => chartVersion.version === version,
);
return chartVersion ? chartVersion.repo : "";
},
});
},
});
export default toHelmReleaseInjectable;

View File

@ -0,0 +1,48 @@
/**
* 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 { load } from "js-yaml";
import releasesInjectable from "../../components/+helm-releases/releases.injectable";
import apiBaseInjectable from "../api-base.injectable";
import type { HelmReleaseDetails } from "../helm-releases.api";
import { helmReleasesUrl } from "../helm-releases.api";
export interface HelmReleaseUpdatePayload {
repo: string;
chart: string;
version: string;
values: string;
}
export interface HelmReleaseUpdateDetails {
log: string;
release: HelmReleaseDetails;
}
export type UpdateHelmRelease = (name: string, namespace: string, payload: HelmReleaseUpdatePayload) => Promise<HelmReleaseUpdateDetails>;
const updateHelmReleaseInjectable = getInjectable({
id: "update-helm-release",
instantiate: (di): UpdateHelmRelease => {
const apiBase = di.inject(apiBaseInjectable);
const releases = di.inject(releasesInjectable);
return async (name, namespace, { repo, chart, values, ...data }) => {
const result = await apiBase.put(helmReleasesUrl({ name, namespace }), {
data: {
chart: `${repo}/${chart}`,
values: load(values),
...data,
},
}) as HelmReleaseUpdateDetails;
releases.invalidate();
return result;
};
},
});
export default updateHelmReleaseInjectable;