/** * 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, { Component } from "react"; import groupBy from "lodash/groupBy"; import type { IComputedValue } from "mobx"; import { computed, makeObservable, observable } from "mobx"; import { Link } from "react-router-dom"; 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 { Drawer, DrawerItem, DrawerTitle } from "../../drawer"; import { Badge } from "../../badge"; import { cssNames, stopPropagation } from "../../../utils"; import { Observer, observer } from "mobx-react"; import { Spinner } from "../../spinner"; import { Table, TableCell, TableHead, TableRow } from "../../table"; import { Button } from "../../button"; import { Notifications } from "../../notifications"; import type { ThemeStore } from "../../../themes/store"; import type { ApiManager } from "../../../../common/k8s-api/api-manager"; import { SubTitle } from "../../layout/sub-title"; import { Checkbox } from "../../checkbox"; import { MonacoEditor } from "../../monaco-editor"; import type { IAsyncComputed } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react"; 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 releaseDetailsInjectable from "./release-details.injectable"; import releaseValuesInjectable from "./release-values.injectable"; import userSuppliedValuesAreShownInjectable from "./user-supplied-values-are-shown.injectable"; import { KubeObjectAge } from "../../kube-object/age"; import type { KubeJsonApiData } from "../../../../common/k8s-api/kube-json-api"; import { entries } from "../../../../common/utils/objects"; import themeStoreInjectable from "../../../themes/store.injectable"; import type { GetDetailsUrl } from "../../kube-detail-params/get-details-url.injectable"; import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable"; import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable"; import assert from "assert"; export interface ReleaseDetailsProps { hideDetails(): void; } interface Dependencies { release: IComputedValue; releaseDetails: IAsyncComputed; releaseValues: IAsyncComputed; updateRelease: (name: string, namespace: string, payload: HelmReleaseUpdatePayload) => Promise; createUpgradeChartTab: (release: HelmRelease) => void; userSuppliedValuesAreShown: { toggle: () => void; value: boolean }; themeStore: ThemeStore; apiManager: ApiManager; getDetailsUrl: GetDetailsUrl; } @observer class NonInjectedReleaseDetails extends Component { @observable saving = false; private nonSavedValues = ""; constructor(props: ReleaseDetailsProps & Dependencies) { super(props); makeObservable(this); } @computed get details() { const details = this.props.releaseDetails.value.get(); assert(details); return details; } updateValues = async (release: HelmRelease) => { const name = release.getName(); const namespace = release.getNs(); const data = { chart: release.getChart(), repo: await release.getRepo(), version: release.getVersion(), values: this.nonSavedValues, }; this.saving = true; try { await this.props.updateRelease(name, namespace, data); Notifications.ok(

Release {name} {" successfully updated!"}

, ); this.props.releaseValues.invalidate(); } catch (err) { Notifications.checkedError(err, "Unknown error occured while updating release"); } this.saving = false; }; upgradeVersion = (release: HelmRelease) => { const { hideDetails, createUpgradeChartTab } = this.props; createUpgradeChartTab(release); hideDetails(); }; renderValues(release: HelmRelease) { return ( {() => { const { saving } = this; const releaseValuesArePending = this.props.releaseValues.pending.get(); this.nonSavedValues = this.props.releaseValues.value.get(); return (
Values
(this.nonSavedValues = text)} />
); }}
); } renderNotes() { if (!this.details.info?.notes) return null; const { notes } = this.details.info; return (
{notes}
); } renderResources(resources: KubeJsonApiData[]) { const { apiManager, getDetailsUrl } = this.props; return (
{ entries(groupBy(resources, item => item.kind)) .map(([kind, items]) => ( Name {items[0].metadata.namespace && Namespace} Age {items.map(item => { const { name, namespace, uid } = item.metadata; const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == item.apiVersion); const detailsUrl = api ? getDetailsUrl(api.getUrl({ name, namespace })) : ""; return ( {detailsUrl ? {name} : name} {namespace && ( {namespace} )} ); })}
)) }
); } renderContent(release: HelmRelease) { if (this.props.releaseDetails.pending.get()) { return ; } const { resources } = this.details; return (
{release.getChart()}
{release.getUpdated()} {` ago (${release.updated})`} {release.getNs()}
{release.getVersion()}
{this.renderValues(release)} Notes {this.renderNotes()} Resources {resources && this.renderResources(resources)}
); } render() { const { hideDetails, themeStore } = this.props; const release = this.props.release.get(); return ( )} > {release && this.renderContent(release)} ); } } export const ReleaseDetails = withInjectables(NonInjectedReleaseDetails, { getProps: (di, props) => ({ ...props, release: di.inject(releaseInjectable), releaseDetails: di.inject(releaseDetailsInjectable), releaseValues: di.inject(releaseValuesInjectable), userSuppliedValuesAreShown: di.inject(userSuppliedValuesAreShownInjectable), updateRelease: di.inject(updateReleaseInjectable), createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable), themeStore: di.inject(themeStoreInjectable), apiManager: di.inject(apiManagerInjectable), getDetailsUrl: di.inject(getDetailsUrlInjectable), }), });