mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
* 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>
211 lines
6.2 KiB
TypeScript
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,
|
|
}),
|
|
},
|
|
);
|