1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00
lens/src/renderer/components/+helm-charts/helm-chart-details.tsx
Iku-turso a277cfcf02
Technical requirements for behavioural unit tests (#5084)
* Implement a lot of technical requirements for behavioural unit tests

Note: the crux of this was to make routing env-agnostic, and not based on URLs as magic strings, but instead something type-enforced.

Note: extension-based routes comply to same exact interface by "late-registering" their routes when installed. Routes are just injectables.

Note: another chunk of global shared state is no more.

Note: a lot of explicit side effects have been cornered to injectables.

Note: a lot of stuff has become reactive as part if this.

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make a directory commonly available

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Require id for <Select /> to prevent non-deterministic renders

This was caused by global state in a 3rd party lib: "react-select".

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Specify id for all <Select /> to satisfy previous commit

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Prevent explicit side effect in component by using existing dependency instead

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Extract instantiation of "conf" as injectables for causing side effects

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Introduce a legacy-helper to make gradual refactoring of inheritors of Singleton easier

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make legacy unit tests for hotbar green and more simple by using the new legacy helper

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Temporarily kludge all unit tests green with a disclaimer about allowing side-effects

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove kludge in previous commit by explicitly permitting specific side effects where old unit tests require it

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Prevent old unit test with side effects from accessing file system

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Migrate to actual typing for di.permitSideEffects

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Prevent unit tests from failing because of non-standard method of HTML-element not present in js-dom

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Adapt integration tests to recent changes

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Fix code style

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Fix artifact from bad rebase

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Add a deprecation from a review comment

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove change that is not required

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant comment

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix code style

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant file

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix bad merge

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Improve variable name

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Tweak logger interface to be more descriptive

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make injecting legacy singleton always provide new instance

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove conditional typing when not needed

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Improve naming of variable

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove unnecessary code style changes

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove flag for causing side effects from too broad scope

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Override side-effects in unit test using injectable instead of monkey patching

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Flag some side-effects and add general overrides

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Fix unit tests in CI by removing explicit side-effect

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove explicit side-effect from getting default shell

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce abstraction for getting absolute paths

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using abstraction for getting absolute path to control explicit side effect

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce abstraction for joining paths

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using abstraction for joining paths to control explicit side effect

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix fake implementation for join paths

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix test after removing explicit side effect

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove explicit side effects from kubeconfig-syncs

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix arguments after removing explicit side effect

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make registrators not async for not being needed anymore

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make generalCatalogEntities non-observable, as there is no requirement

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove redundant code

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Simplify logic for registering general catalog entity sources

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Add TODO

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Replace function for getting application menu items with reactive solution

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix typo in interface name

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove global shared state usages of hot bar store

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant enum

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
2022-03-31 16:57:05 +03:00

211 lines
6.2 KiB
TypeScript

/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import "./helm-chart-details.scss";
import React, { Component } from "react";
import { getChartDetails, HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
import { observable, makeObservable, reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { Drawer, DrawerItem } from "../drawer";
import { boundMethod, stopPropagation } from "../../utils";
import { MarkdownViewer } from "../markdown-viewer";
import { Spinner } from "../spinner";
import { Button } from "../button";
import { Select, type SelectOption } from "../select";
import { Badge } from "../badge";
import { Tooltip, withStyles } from "@material-ui/core";
import { withInjectables } from "@ogre-tools/injectable-react";
import createInstallChartTabInjectable from "../dock/install-chart/create-install-chart-tab.injectable";
import { Notifications } from "../notifications";
export interface HelmChartDetailsProps {
chart: HelmChart;
hideDetails(): void;
}
const LargeTooltip = withStyles({
tooltip: {
fontSize: "var(--font-size-small)",
},
})(Tooltip);
interface Dependencies {
createInstallChartTab: (helmChart: HelmChart) => void;
}
@observer
class NonInjectedHelmChartDetails extends Component<HelmChartDetailsProps & Dependencies> {
@observable chartVersions: HelmChart[];
@observable selectedChart?: HelmChart;
@observable readme?: string;
private abortController?: AbortController;
constructor(props: HelmChartDetailsProps & Dependencies) {
super(props);
makeObservable(this);
}
componentWillUnmount() {
this.abortController?.abort();
}
componentDidMount() {
disposeOnUnmount(this, [
reaction(() => this.props.chart, async ({ name, repo, version }) => {
try {
this.selectedChart = undefined;
this.chartVersions = undefined;
this.readme = undefined;
const { readme, versions } = await getChartDetails(repo, name, { version });
this.readme = readme;
this.chartVersions = versions;
this.selectedChart = versions[0];
} catch (error) {
Notifications.error(error);
this.selectedChart = null;
}
}, {
fireImmediately: true,
}),
]);
}
@boundMethod
async onVersionChange({ value: chart }: SelectOption<HelmChart>) {
this.selectedChart = chart;
this.readme = null;
try {
this.abortController?.abort();
this.abortController = new AbortController();
const { chart: { name, repo }} = this.props;
const { readme } = await getChartDetails(repo, name, { version: chart.version, reqInit: { signal: this.abortController.signal }});
this.readme = readme;
} catch (error) {
Notifications.error(error);
}
}
@boundMethod
install() {
this.props.createInstallChartTab(this.selectedChart);
this.props.hideDetails();
}
renderIntroduction() {
const { selectedChart, chartVersions, onVersionChange } = this;
const placeholder = require("./helm-placeholder.svg");
return (
<div className="introduction flex align-flex-start">
<img
className="intro-logo"
src={selectedChart.getIcon() || placeholder}
onError={(event) => event.currentTarget.src = placeholder}
/>
<div className="intro-contents box grow">
<div className="description flex align-center justify-space-between">
{selectedChart.getDescription()}
<Button primary label="Install" onClick={this.install} />
</div>
<DrawerItem name="Version" className="version" onClick={stopPropagation}>
<Select
id="chart-version-input"
themeName="outlined"
menuPortalTarget={null}
options={chartVersions.map(chart => ({
label: (
chart.deprecated
? (
<LargeTooltip title="Deprecated" placement="left">
<span className="deprecated">{chart.version}</span>
</LargeTooltip>
)
: chart.version
),
value: chart,
}))}
isOptionDisabled={({ value: chart }) => chart.deprecated}
value={selectedChart}
onChange={onVersionChange}
/>
</DrawerItem>
<DrawerItem name="Home">
<a href={selectedChart.getHome()} target="_blank" rel="noreferrer">{selectedChart.getHome()}</a>
</DrawerItem>
<DrawerItem name="Maintainers" className="maintainers">
{selectedChart.getMaintainers().map(({ name, email, url }) =>
<a key={name} href={url || `mailto:${email}`} target="_blank" rel="noreferrer">{name}</a>,
)}
</DrawerItem>
{selectedChart.getKeywords().length > 0 && (
<DrawerItem name="Keywords" labelsOnly>
{selectedChart.getKeywords().map(key => <Badge key={key} label={key} />)}
</DrawerItem>
)}
</div>
</div>
);
}
renderReadme() {
if (this.readme === null) {
return <Spinner center />;
}
return (
<div className="chart-description">
<MarkdownViewer markdown={this.readme} />
</div>
);
}
renderContent() {
if (!this.selectedChart) {
return <Spinner center />;
}
return (
<div className="box grow">
{this.renderIntroduction()}
{this.renderReadme()}
</div>
);
}
render() {
const { chart, hideDetails } = this.props;
const title = chart ? `Chart: ${chart.getFullName()}` : "";
return (
<Drawer
className="HelmChartDetails"
usePortal={true}
open={!!chart}
title={title}
onClose={hideDetails}
>
{this.renderContent()}
</Drawer>
);
}
}
export const HelmChartDetails = withInjectables<Dependencies, HelmChartDetailsProps>(
NonInjectedHelmChartDetails,
{
getProps: (di, props) => ({
createInstallChartTab: di.inject(createInstallChartTabInjectable),
...props,
}),
},
);