mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Reorganize code to get rid of orphan promise
Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
2e6178760f
commit
2120915bf3
File diff suppressed because it is too large
Load Diff
@ -288,15 +288,42 @@ describe("showing details for helm release", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("when release resolve with no data, renders", async () => {
|
||||
await callForHelmReleaseMock.resolve(undefined);
|
||||
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
describe("when call for release resolves with error", () => {
|
||||
beforeEach(async () => {
|
||||
await callForHelmReleaseMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: "some-error",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", async () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-release-detail-content-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows error message about missing release", () => {
|
||||
expect(
|
||||
rendered.getByTestId("helm-release-detail-error"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not call for release configuration", () => {
|
||||
expect(callForHelmReleaseConfigurationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when details resolve", () => {
|
||||
describe("when call for release resolve with release", () => {
|
||||
beforeEach(async () => {
|
||||
await callForHelmReleaseMock.resolve(detailedReleaseFake);
|
||||
await callForHelmReleaseMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: detailedReleaseFake,
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
|
||||
@ -8,8 +8,8 @@ import "./release-details.scss";
|
||||
import React from "react";
|
||||
|
||||
import { Link } from "react-router-dom";
|
||||
import { Drawer, DrawerItem, DrawerTitle } from "../../drawer";
|
||||
import { cssNames, stopPropagation } from "../../../utils";
|
||||
import { DrawerItem, DrawerTitle } from "../../drawer";
|
||||
import { stopPropagation } from "../../../utils";
|
||||
import { observer } from "mobx-react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { ConfigurationInput, MinimalResourceGroup, OnlyUserSuppliedValuesAreShownToggle, ReleaseDetailsModel } from "./release-details-model/release-details-model.injectable";
|
||||
@ -20,7 +20,6 @@ import { Badge } from "../../badge";
|
||||
import { SubTitle } from "../../layout/sub-title";
|
||||
import { Table, TableCell, TableHead, TableRow } from "../../table";
|
||||
import { ReactiveDuration } from "../../duration/reactive-duration";
|
||||
import { HelmReleaseMenu } from "../release-menu";
|
||||
import { Checkbox } from "../../checkbox";
|
||||
import { MonacoEditor } from "../../monaco-editor";
|
||||
import { Spinner } from "../../spinner";
|
||||
@ -36,96 +35,85 @@ interface Dependencies {
|
||||
|
||||
const NonInjectedReleaseDetailsContent = observer(({ model }: Dependencies & ReleaseDetailsContentProps) => {
|
||||
const isLoading = model.isLoading.get();
|
||||
const failedToLoad = model.failedToLoad.get();
|
||||
|
||||
if (failedToLoad) {
|
||||
return <div data-testid="helm-release-detail-error">Failed to load release</div>;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
className={cssNames("ReleaseDetails", model.activeTheme)}
|
||||
usePortal={true}
|
||||
open={true}
|
||||
title={isLoading ? "" : model.release.getName()}
|
||||
onClose={model.close}
|
||||
testIdForClose="close-helm-release-detail"
|
||||
toolbar={
|
||||
!isLoading && (
|
||||
<HelmReleaseMenu
|
||||
release={model.release}
|
||||
toolbar
|
||||
hideDetails={model.close}
|
||||
/>
|
||||
)
|
||||
}
|
||||
data-testid={`helm-release-details-for-${model.id}`}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Spinner center data-testid="helm-release-detail-content-spinner" />
|
||||
) : (
|
||||
<div>
|
||||
<DrawerItem name="Chart" className="chart">
|
||||
<div className="flex gaps align-center">
|
||||
<span>{model.release.chart}</span>
|
||||
(isLoading ? (
|
||||
<Spinner center data-testid="helm-release-detail-content-spinner" />
|
||||
) : (
|
||||
<div>
|
||||
<DrawerItem name="Chart" className="chart">
|
||||
<div className="flex gaps align-center">
|
||||
<span>{model.release.chart}</span>
|
||||
|
||||
<Button
|
||||
primary
|
||||
label="Upgrade"
|
||||
className="box right upgrade"
|
||||
onClick={model.startUpgradeProcess}
|
||||
data-testid="helm-release-upgrade-button"
|
||||
/>
|
||||
</div>
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerItem name="Updated">
|
||||
{model.release.getUpdated()}
|
||||
{` ago (${model.release.updated})`}
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerItem name="Namespace">{model.release.getNs()}</DrawerItem>
|
||||
|
||||
<DrawerItem name="Version" onClick={stopPropagation}>
|
||||
<div className="version flex gaps align-center">
|
||||
<span>{model.release.getVersion()}</span>
|
||||
</div>
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerItem
|
||||
name="Status"
|
||||
className="status"
|
||||
labelsOnly>
|
||||
<Badge
|
||||
label={model.release.getStatus()}
|
||||
className={kebabCase(model.release.getStatus())}
|
||||
<Button
|
||||
primary
|
||||
label="Upgrade"
|
||||
className="box right upgrade"
|
||||
onClick={model.startUpgradeProcess}
|
||||
data-testid="helm-release-upgrade-button"
|
||||
/>
|
||||
</DrawerItem>
|
||||
</div>
|
||||
</DrawerItem>
|
||||
|
||||
<ReleaseValues
|
||||
configuration={model.configuration}
|
||||
onlyUserSuppliedValuesAreShown={
|
||||
model.onlyUserSuppliedValuesAreShown
|
||||
}
|
||||
<DrawerItem name="Updated">
|
||||
{model.release.getUpdated()}
|
||||
{` ago (${model.release.updated})`}
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerItem name="Namespace">{model.release.getNs()}</DrawerItem>
|
||||
|
||||
<DrawerItem name="Version" onClick={stopPropagation}>
|
||||
<div className="version flex gaps align-center">
|
||||
<span>{model.release.getVersion()}</span>
|
||||
</div>
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerItem
|
||||
name="Status"
|
||||
className="status"
|
||||
labelsOnly>
|
||||
<Badge
|
||||
label={model.release.getStatus()}
|
||||
className={kebabCase(model.release.getStatus())}
|
||||
/>
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerTitle>Notes</DrawerTitle>
|
||||
<ReleaseValues
|
||||
configuration={model.configuration}
|
||||
onlyUserSuppliedValuesAreShown={
|
||||
model.onlyUserSuppliedValuesAreShown
|
||||
}
|
||||
/>
|
||||
|
||||
{model.notes && <div className="notes">{model.notes}</div>}
|
||||
<DrawerTitle>Notes</DrawerTitle>
|
||||
|
||||
<DrawerTitle>Resources</DrawerTitle>
|
||||
{model.notes && <div className="notes">{model.notes}</div>}
|
||||
|
||||
{model.groupedResources.length > 0 && (
|
||||
<div className="resources">
|
||||
{model.groupedResources.map((group) => (
|
||||
<ResourceGroup key={group.kind} group={group} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Drawer>
|
||||
<DrawerTitle>Resources</DrawerTitle>
|
||||
|
||||
{model.groupedResources.length > 0 && (
|
||||
<div className="resources">
|
||||
{model.groupedResources.map((group) => (
|
||||
<ResourceGroup key={group.kind} group={group} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
});
|
||||
|
||||
export const ReleaseDetailsContent = withInjectables<Dependencies, ReleaseDetailsContentProps>(NonInjectedReleaseDetailsContent, {
|
||||
getProps: (di, props) => ({
|
||||
model: di.inject(releaseDetailsModelInjectable, props.targetRelease),
|
||||
getPlaceholder: () => <Spinner center data-testid="helm-release-detail-content-spinner" />,
|
||||
|
||||
getProps: async (di, props) => ({
|
||||
model: await di.inject(releaseDetailsModelInjectable, props.targetRelease),
|
||||
...props,
|
||||
}),
|
||||
});
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./release-details.scss";
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { TargetHelmRelease } from "./target-helm-release.injectable";
|
||||
import navigateToHelmReleasesInjectable from "../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import type { ReleaseDetailsModel } from "./release-details-model/release-details-model.injectable";
|
||||
import releaseDetailsModelInjectable from "./release-details-model/release-details-model.injectable";
|
||||
import { HelmReleaseMenu } from "../release-menu";
|
||||
|
||||
interface ReleaseDetailsDrawerProps {
|
||||
targetRelease: TargetHelmRelease;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
model: ReleaseDetailsModel;
|
||||
closeDrawer: () => void;
|
||||
}
|
||||
|
||||
const NonInjectedReleaseDetailsDrawerToolbar = observer(
|
||||
({ model, closeDrawer }: Dependencies & ReleaseDetailsDrawerProps) =>
|
||||
model.failedToLoad.get() ? null : (
|
||||
<HelmReleaseMenu
|
||||
release={model.release}
|
||||
toolbar
|
||||
hideDetails={closeDrawer}
|
||||
/>
|
||||
),
|
||||
);
|
||||
|
||||
export const ReleaseDetailsDrawerToolbar = withInjectables<
|
||||
Dependencies,
|
||||
ReleaseDetailsDrawerProps
|
||||
>(NonInjectedReleaseDetailsDrawerToolbar, {
|
||||
getPlaceholder: () => <></>,
|
||||
|
||||
getProps: async (di, props) => ({
|
||||
model: await di.inject(releaseDetailsModelInjectable, props.targetRelease),
|
||||
closeDrawer: di.inject(navigateToHelmReleasesInjectable),
|
||||
...props,
|
||||
}),
|
||||
});
|
||||
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./release-details.scss";
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Drawer } from "../../drawer";
|
||||
import { cssNames } from "../../../utils";
|
||||
import { observer } from "mobx-react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { TargetHelmRelease } from "./target-helm-release.injectable";
|
||||
import type { ActiveThemeType } from "../../../themes/active-type.injectable";
|
||||
import activeThemeTypeInjectable from "../../../themes/active-type.injectable";
|
||||
import { ReleaseDetailsContent } from "./release-details-content";
|
||||
import navigateToHelmReleasesInjectable from "../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import { ReleaseDetailsDrawerToolbar } from "./release-details-drawer-toolbar";
|
||||
|
||||
interface ReleaseDetailsDrawerProps {
|
||||
targetRelease: TargetHelmRelease;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
activeThemeType: ActiveThemeType;
|
||||
closeDrawer: () => void;
|
||||
}
|
||||
|
||||
const NonInjectedReleaseDetailsDrawer = observer(({
|
||||
activeThemeType,
|
||||
closeDrawer,
|
||||
targetRelease,
|
||||
}: Dependencies & ReleaseDetailsDrawerProps) => (
|
||||
<Drawer
|
||||
className={cssNames("ReleaseDetails", activeThemeType.get())}
|
||||
usePortal={true}
|
||||
open={true}
|
||||
title={targetRelease.name}
|
||||
onClose={closeDrawer}
|
||||
testIdForClose="close-helm-release-detail"
|
||||
toolbar={<ReleaseDetailsDrawerToolbar targetRelease={targetRelease} />}
|
||||
data-testid={`helm-release-details-for-${targetRelease.namespace}/${targetRelease.name}`}
|
||||
>
|
||||
<ReleaseDetailsContent targetRelease={targetRelease} />
|
||||
</Drawer>
|
||||
));
|
||||
|
||||
export const ReleaseDetailsDrawer = withInjectables<
|
||||
Dependencies,
|
||||
ReleaseDetailsDrawerProps
|
||||
>(NonInjectedReleaseDetailsDrawer, {
|
||||
getProps: (di, props) => ({
|
||||
activeThemeType: di.inject(activeThemeTypeInjectable),
|
||||
closeDrawer: di.inject(navigateToHelmReleasesInjectable),
|
||||
...props,
|
||||
}),
|
||||
});
|
||||
@ -7,6 +7,7 @@ import type { HelmReleaseDto } from "../../../../../../common/k8s-api/endpoints/
|
||||
import callForHelmReleasesInjectable from "../../../call-for-helm-releases/call-for-helm-releases.injectable";
|
||||
import type { HelmReleaseDetails } from "./call-for-helm-release-details/call-for-helm-release-details.injectable";
|
||||
import callForHelmReleaseDetailsInjectable from "./call-for-helm-release-details/call-for-helm-release-details.injectable";
|
||||
import type { AsyncResult } from "../../../../../../common/utils/async-result";
|
||||
|
||||
export interface DetailedHelmRelease {
|
||||
release: HelmReleaseDto;
|
||||
@ -16,7 +17,7 @@ export interface DetailedHelmRelease {
|
||||
export type CallForHelmRelease = (
|
||||
name: string,
|
||||
namespace: string
|
||||
) => Promise<DetailedHelmRelease | undefined>;
|
||||
) => Promise<AsyncResult<DetailedHelmRelease | undefined>>;
|
||||
|
||||
const callForHelmReleaseInjectable = getInjectable({
|
||||
id: "call-for-helm-release",
|
||||
@ -36,10 +37,13 @@ const callForHelmReleaseInjectable = getInjectable({
|
||||
);
|
||||
|
||||
if (!release) {
|
||||
return undefined;
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: `Release ${name} didn't exist in ${namespace} namespace.`,
|
||||
};
|
||||
}
|
||||
|
||||
return { release, details };
|
||||
return { callWasSuccessful: true, response: { release, details }};
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -26,16 +26,14 @@ import showSuccessNotificationInjectable from "../../../notifications/show-succe
|
||||
import React from "react";
|
||||
import createUpgradeChartTabInjectable from "../../../dock/upgrade-chart/create-upgrade-chart-tab.injectable";
|
||||
import type { HelmRelease } from "../../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||
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 assert from "assert";
|
||||
import withOrphanPromiseInjectable from "../../../../../common/utils/with-orphan-promise/with-orphan-promise.injectable";
|
||||
import activeThemeInjectable from "../../../../themes/active.injectable";
|
||||
|
||||
const releaseDetailsModelInjectable = getInjectable({
|
||||
id: "release-details-model",
|
||||
|
||||
instantiate: (di, targetRelease: TargetHelmRelease) => {
|
||||
instantiate: async (di, targetRelease: TargetHelmRelease) => {
|
||||
const callForHelmRelease = di.inject(callForHelmReleaseInjectable);
|
||||
const callForHelmReleaseConfiguration = di.inject(callForHelmReleaseConfigurationInjectable);
|
||||
const activeTheme = di.inject(activeThemeInjectable);
|
||||
@ -45,7 +43,6 @@ const releaseDetailsModelInjectable = getInjectable({
|
||||
const showSuccessNotification = di.inject(showSuccessNotificationInjectable);
|
||||
const createUpgradeChartTab = di.inject(createUpgradeChartTabInjectable);
|
||||
const navigateToHelmReleases = di.inject(navigateToHelmReleasesInjectable);
|
||||
const withOrphanPromise = di.inject(withOrphanPromiseInjectable);
|
||||
|
||||
const model = new ReleaseDetailsModel({
|
||||
callForHelmRelease,
|
||||
@ -57,13 +54,10 @@ const releaseDetailsModelInjectable = getInjectable({
|
||||
showCheckedErrorNotification,
|
||||
showSuccessNotification,
|
||||
createUpgradeChartTab,
|
||||
navigateToHelmReleases,
|
||||
closeDrawer: navigateToHelmReleases,
|
||||
});
|
||||
|
||||
const load = withOrphanPromise(model.load);
|
||||
|
||||
// TODO: Reorganize Drawer to allow setting of header-bar in children to make "getPlaceholder" from injectable usable.
|
||||
load();
|
||||
await model.load();
|
||||
|
||||
return model;
|
||||
},
|
||||
@ -99,7 +93,7 @@ interface Dependencies {
|
||||
showCheckedErrorNotification: ShowCheckedErrorNotification;
|
||||
showSuccessNotification: ShowNotification;
|
||||
createUpgradeChartTab: (release: HelmRelease) => string;
|
||||
navigateToHelmReleases: NavigateToHelmReleases;
|
||||
closeDrawer: () => void;
|
||||
}
|
||||
|
||||
export class ReleaseDetailsModel {
|
||||
@ -110,6 +104,7 @@ export class ReleaseDetailsModel {
|
||||
private detailedRelease = observable.box<DetailedHelmRelease | undefined>();
|
||||
|
||||
readonly isLoading = observable.box(false);
|
||||
readonly failedToLoad = observable.box(false);
|
||||
|
||||
readonly configuration: ConfigurationInput = {
|
||||
nonSavedValue: observable.box(""),
|
||||
@ -182,13 +177,21 @@ export class ReleaseDetailsModel {
|
||||
|
||||
const { name, namespace } = this.dependencies.targetRelease;
|
||||
|
||||
const detailedRelease = await this.dependencies.callForHelmRelease(
|
||||
const result = await this.dependencies.callForHelmRelease(
|
||||
name,
|
||||
namespace,
|
||||
);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
runInAction(() => {
|
||||
this.failedToLoad.set(true);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
runInAction(() => {
|
||||
this.detailedRelease.set(detailedRelease);
|
||||
this.detailedRelease.set(result.response);
|
||||
});
|
||||
|
||||
await this.loadConfiguration();
|
||||
@ -263,13 +266,13 @@ export class ReleaseDetailsModel {
|
||||
}
|
||||
|
||||
close = () => {
|
||||
this.dependencies.navigateToHelmReleases();
|
||||
this.dependencies.closeDrawer();
|
||||
};
|
||||
|
||||
startUpgradeProcess = () => {
|
||||
this.dependencies.createUpgradeChartTab(this.release);
|
||||
|
||||
this.close();
|
||||
this.dependencies.closeDrawer();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -11,9 +11,9 @@ import { observer } from "mobx-react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { ReleaseDetailsContent } from "./release-details-content";
|
||||
import type { TargetHelmRelease } from "./target-helm-release.injectable";
|
||||
import targetHelmReleaseInjectable from "./target-helm-release.injectable";
|
||||
import { ReleaseDetailsDrawer } from "./release-details-drawer";
|
||||
|
||||
interface Dependencies {
|
||||
targetRelease: IComputedValue<
|
||||
@ -25,7 +25,7 @@ const NonInjectedReleaseDetails = observer(
|
||||
({ targetRelease }: Dependencies) => {
|
||||
const release = targetRelease.get();
|
||||
|
||||
return release ? <ReleaseDetailsContent targetRelease={release} /> : null;
|
||||
return release ? <ReleaseDetailsDrawer targetRelease={release} /> : null;
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
23
src/renderer/themes/active-type.injectable.ts
Normal file
23
src/renderer/themes/active-type.injectable.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 { IComputedValue } from "mobx";
|
||||
import { computed } from "mobx";
|
||||
import type { LensThemeType } from "./store";
|
||||
import themeStoreInjectable from "./store.injectable";
|
||||
|
||||
export type ActiveThemeType = IComputedValue<LensThemeType>;
|
||||
|
||||
const activeThemeTypeInjectable = getInjectable({
|
||||
id: "active-theme-type",
|
||||
|
||||
instantiate: (di) => {
|
||||
const store = di.inject(themeStoreInjectable);
|
||||
|
||||
return computed(() => store.activeTheme.type);
|
||||
},
|
||||
});
|
||||
|
||||
export default activeThemeTypeInjectable;
|
||||
@ -17,10 +17,10 @@ import type { ReadonlyDeep } from "type-fest/source/readonly-deep";
|
||||
import assert from "assert";
|
||||
|
||||
export type ThemeId = string;
|
||||
|
||||
export type LensThemeType = "dark" | "light";
|
||||
export interface LensTheme {
|
||||
name: string;
|
||||
type: "dark" | "light";
|
||||
type: LensThemeType;
|
||||
colors: Record<string, string>;
|
||||
description: string;
|
||||
author: string;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user