diff --git a/src/common/k8s-api/api-manager/index.ts b/src/common/k8s-api/api-manager/index.ts index 105a0f0c9f..56182e815b 100644 --- a/src/common/k8s-api/api-manager/index.ts +++ b/src/common/k8s-api/api-manager/index.ts @@ -4,4 +4,3 @@ */ export * from "./api-manager"; -export * from "./legacy-global"; diff --git a/src/common/k8s-api/kube-api.ts b/src/common/k8s-api/kube-api.ts index 8ee1800930..0e62539d0a 100644 --- a/src/common/k8s-api/kube-api.ts +++ b/src/common/k8s-api/kube-api.ts @@ -8,7 +8,6 @@ import { isFunction, merge } from "lodash"; import { stringify } from "querystring"; import { apiKubePrefix, isDevelopment } from "../../common/vars"; -import { apiManager } from "./api-manager"; import { apiBase, apiKube } from "./index"; import { createKubeApiURL, parseKubeApi } from "./kube-api-parse"; import type { KubeObjectConstructor, KubeJsonApiDataFor, KubeObjectMetadata, KubeObjectScope } from "./kube-object"; @@ -27,6 +26,8 @@ import type { Patch } from "rfc6902"; import assert from "assert"; import type { PartialDeep } from "type-fest"; import logger from "../logger"; +import { Environments, getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; +import apiManagerInjectable from "./api-manager/manager.injectable"; /** * The options used for creating a `KubeApi` @@ -307,6 +308,22 @@ export interface DeleteResourceDescriptor extends ResourceDescriptor { propagationPolicy?: PropagationPolicy; } +/** + * @deprecated In the new extension API, don't expose `KubeApi`'s constructor + */ +function legacyRegisterApi(apiBase: string, api: KubeApi): void { + // Try both just in case, because we might be in a testing environment + for (const env of [Environments.main, Environments.renderer]) { + const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(env); + + if (di) { + const apiManager = di.inject(apiManagerInjectable); + + apiManager.registerApi(apiBase, api); + } + } +} + export class KubeApi< Object extends KubeObject = KubeObject, Data extends KubeJsonApiDataFor = KubeJsonApiDataFor, @@ -359,7 +376,7 @@ export class KubeApi< this.request = request; this.objectConstructor = objectConstructor; this.parseResponse = this.parseResponse.bind(this); - apiManager.registerApi>(apiBase, this); + legacyRegisterApi(apiBase, this as unknown as KubeApi); } get apiVersionWithGroup() { @@ -440,7 +457,7 @@ export class KubeApi< if (this.apiVersionPreferred) { this.apiBase = this.computeApiBase(); - apiManager.registerApi>(this.apiBase, this); + legacyRegisterApi(this.apiBase, this as unknown as KubeApi); } } } diff --git a/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts index aeb31d57cd..9f2bc8b13c 100644 --- a/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts +++ b/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts @@ -3,7 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { DiContainer } from "@ogre-tools/injectable"; -import assert from "assert"; import { iter } from "../../common/utils"; const legacyGlobalDis = new Map(); @@ -35,9 +34,5 @@ export const getLegacyGlobalDiForExtensionApi = () => { }; export function getEnvironmentSpecificLegacyGlobalDiForExtensionApi(environment: Environments) { - const di = legacyGlobalDis.get(environment); - - assert(di, `missing di for environment=${Environments[environment]}`); - - return di; + return legacyGlobalDis.get(environment); } diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index 076ce13a3f..c265085489 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -15,22 +15,30 @@ import { cssNames } from "../../utils"; import type { HorizontalPodAutoscalerMetricSpec, HorizontalPodAutoscalerMetricTarget } from "../../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api"; import { HorizontalPodAutoscaler, HpaMetricType } from "../../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { ApiManager } from "../../../common/k8s-api/api-manager"; import { KubeObjectMeta } from "../kube-object-meta"; -import { getDetailsUrl } from "../kube-detail-params"; import logger from "../../../common/logger"; +import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable"; +import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable"; export interface HpaDetailsProps extends KubeObjectDetailsProps { } +interface Dependencies { + apiManager: ApiManager; + getDetailsUrl: GetDetailsUrl; +} + @observer -export class HpaDetails extends React.Component { +class NonInjectedHpaDetails extends React.Component { private renderTargetLink(target: HorizontalPodAutoscalerMetricTarget | undefined) { if (!target) { return null; } - const { object: hpa } = this.props; + const { object: hpa, apiManager, getDetailsUrl } = this.props; const { kind, name } = target; const objectUrl = getDetailsUrl(apiManager.lookupApiLink(target, hpa)); @@ -119,7 +127,7 @@ export class HpaDetails extends React.Component { } render() { - const { object: hpa } = this.props; + const { object: hpa, apiManager, getDetailsUrl } = this.props; if (!hpa) { return null; @@ -183,3 +191,11 @@ export class HpaDetails extends React.Component { ); } } + +export const HpaDetails = withInjectables(NonInjectedHpaDetails, { + getProps: (di, props) => ({ + ...props, + apiManager: di.inject(apiManagerInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), + }), +}); diff --git a/src/renderer/components/+events/event-details.tsx b/src/renderer/components/+events/event-details.tsx index 9227b3e73e..cf45d7a666 100644 --- a/src/renderer/components/+events/event-details.tsx +++ b/src/renderer/components/+events/event-details.tsx @@ -14,78 +14,95 @@ import type { KubeObjectDetailsProps } from "../kube-object-details"; import { KubeEvent } from "../../../common/k8s-api/endpoints/events.api"; import { KubeObjectMeta } from "../kube-object-meta"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { getDetailsUrl } from "../kube-detail-params"; -import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { ApiManager } from "../../../common/k8s-api/api-manager"; import logger from "../../../common/logger"; import { DurationAbsoluteTimestamp } from "./duration-absolute"; +import { withInjectables } from "@ogre-tools/injectable-react"; +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 { cssNames } from "../../utils"; export interface EventDetailsProps extends KubeObjectDetailsProps { } -@observer -export class EventDetails extends React.Component { - render() { - const { object: event } = this.props; - - if (!event) { - return null; - } - - if (!(event instanceof KubeEvent)) { - logger.error("[EventDetails]: passed object that is not an instanceof KubeEvent", event); - - return null; - } - - const { message, reason, count, type, involvedObject } = event; - const { kind, name, namespace, fieldPath } = involvedObject; - - return ( -
- - - - {message} - - - {reason} - - - {event.getSource()} - - - - - - - - - {count} - - - {type} - - - Involved object - - - Name - Namespace - Kind - Field Path - - - - - {name} - - - {namespace} - {kind} - {fieldPath} - -
-
- ); - } +interface Dependencies { + getDetailsUrl: GetDetailsUrl; + apiManager: ApiManager; } + +const NonInjectedEventDetails = observer(({ + apiManager, + getDetailsUrl, + object: event, + className, +}: Dependencies & EventDetailsProps) => { + if (!event) { + return null; + } + + if (!(event instanceof KubeEvent)) { + logger.error("[EventDetails]: passed object that is not an instanceof KubeEvent", event); + + return null; + } + + const { message, reason, count, type, involvedObject } = event; + const { kind, name, namespace, fieldPath } = involvedObject; + + return ( +
+ + + + {message} + + + {reason} + + + {event.getSource()} + + + + + + + + + {count} + + + {type} + + + Involved object + + + Name + Namespace + Kind + Field Path + + + + + {name} + + + {namespace} + {kind} + {fieldPath} + +
+
+ ); +}); + +export const EventDetails = withInjectables(NonInjectedEventDetails, { + getProps: (di, props) => ({ + ...props, + apiManager: di.inject(apiManagerInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), + }), +}); diff --git a/src/renderer/components/+helm-releases/release-details/release-details.tsx b/src/renderer/components/+helm-releases/release-details/release-details.tsx index 9e1d3f68fe..ee01070fbf 100644 --- a/src/renderer/components/+helm-releases/release-details/release-details.tsx +++ b/src/renderer/components/+helm-releases/release-details/release-details.tsx @@ -22,9 +22,8 @@ import { Table, TableCell, TableHead, TableRow } from "../../table"; import { Button } from "../../button"; import { Notifications } from "../../notifications"; import type { ThemeStore } from "../../../themes/store"; -import { apiManager } from "../../../../common/k8s-api/api-manager"; +import type { ApiManager } from "../../../../common/k8s-api/api-manager"; import { SubTitle } from "../../layout/sub-title"; -import { getDetailsUrl } from "../../kube-detail-params"; import { Checkbox } from "../../checkbox"; import { MonacoEditor } from "../../monaco-editor"; import type { IAsyncComputed } from "@ogre-tools/injectable-react"; @@ -39,6 +38,9 @@ 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"; export interface ReleaseDetailsProps { hideDetails(): void; @@ -52,6 +54,8 @@ interface Dependencies { createUpgradeChartTab: (release: HelmRelease) => void; userSuppliedValuesAreShown: { toggle: () => void; value: boolean }; themeStore: ThemeStore; + apiManager: ApiManager; + getDetailsUrl: GetDetailsUrl; } @observer @@ -158,6 +162,8 @@ class NonInjectedReleaseDetails extends Component { @@ -288,5 +294,7 @@ export const ReleaseDetails = withInjectables updateRelease: di.inject(updateReleaseInjectable), createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable), themeStore: di.inject(themeStoreInjectable), + apiManager: di.inject(apiManagerInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), }), }); diff --git a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx index 44fbfe681a..700f1fdbf8 100644 --- a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx @@ -9,19 +9,27 @@ import React from "react"; import { observer } from "mobx-react"; import type { EndpointSubset, Endpoints, EndpointAddress } from "../../../common/k8s-api/endpoints"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { ApiManager } from "../../../common/k8s-api/api-manager"; import { Link } from "react-router-dom"; -import { getDetailsUrl } from "../kube-detail-params"; import { autoBind } from "../../../common/utils"; +import { withInjectables } from "@ogre-tools/injectable-react"; +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"; export interface EndpointSubsetListProps { subset: Required; endpoint: Endpoints; } +interface Dependencies { + apiManager: ApiManager; + getDetailsUrl: GetDetailsUrl; +} + @observer -export class EndpointSubsetList extends React.Component { - constructor(props: EndpointSubsetListProps) { +class NonInjectedEndpointSubsetList extends React.Component { + constructor(props: EndpointSubsetListProps & Dependencies) { super(props); autoBind(this); } @@ -68,7 +76,7 @@ export class EndpointSubsetList extends React.Component return undefined; } - const { endpoint } = this.props; + const { endpoint, getDetailsUrl, apiManager } = this.props; return ( ); } } + +export const EndpointSubsetList = withInjectables(NonInjectedEndpointSubsetList, { + getProps: (di, props) => ({ + ...props, + apiManager: di.inject(apiManagerInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), + }), +}); diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index 627a99ee6e..b1b7f8cdac 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -8,21 +8,26 @@ import "./pods.scss"; import React, { Fragment } from "react"; import { observer } from "mobx-react"; import { Link } from "react-router-dom"; -import { podStore } from "./legacy-store"; -import { eventStore } from "../+events/legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; -import type { Pod } from "../../../common/k8s-api/endpoints"; -import { nodeApi } from "../../../common/k8s-api/endpoints"; +import type { NodeApi, Pod } from "../../../common/k8s-api/endpoints"; import { StatusBrick } from "../status-brick"; import { cssNames, getConvertedParts, object, stopPropagation } from "../../utils"; import startCase from "lodash/startCase"; import kebabCase from "lodash/kebabCase"; -import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { ApiManager } from "../../../common/k8s-api/api-manager"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { Badge } from "../badge"; -import { getDetailsUrl } from "../kube-detail-params"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { withInjectables } from "@ogre-tools/injectable-react"; +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 type { EventStore } from "../+events/store"; +import type { PodStore } from "./store"; +import nodeApiInjectable from "../../../common/k8s-api/endpoints/node.api.injectable"; +import eventStoreInjectable from "../+events/store.injectable"; +import podStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -36,8 +41,16 @@ enum columnId { status = "status", } +interface Dependencies { + getDetailsUrl: GetDetailsUrl; + apiManager: ApiManager; + eventStore: EventStore; + podStore: PodStore; + nodeApi: NodeApi; +} + @observer -export class Pods extends React.Component { +class NonInjectedPods extends React.Component { renderState(name: string, ready: boolean, key: string, data: Partial> | undefined) { return data && ( <> @@ -87,6 +100,8 @@ export class Pods extends React.Component { } render() { + const { apiManager, getDetailsUrl, podStore, eventStore, nodeApi } = this.props; + return ( (NonInjectedPods, { + getProps: (di, props) => ({ + ...props, + apiManager: di.inject(apiManagerInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), + nodeApi: di.inject(nodeApiInjectable), + eventStore: di.inject(eventStoreInjectable), + podStore: di.inject(podStoreInjectable), + }), +}); diff --git a/src/renderer/components/dock/create-resource/view.tsx b/src/renderer/components/dock/create-resource/view.tsx index 3320d122a0..2dac4e03a9 100644 --- a/src/renderer/components/dock/create-resource/view.tsx +++ b/src/renderer/components/dock/create-resource/view.tsx @@ -17,15 +17,18 @@ import { InfoPanel } from "../info-panel"; import * as resourceApplierApi from "../../../../common/k8s-api/endpoints/resource-applier.api"; import { Notifications } from "../../notifications"; import logger from "../../../../common/logger"; -import { getDetailsUrl } from "../../kube-detail-params"; -import { apiManager } from "../../../../common/k8s-api/api-manager"; +import type { ApiManager } from "../../../../common/k8s-api/api-manager"; import { isString, prevDefault } from "../../../utils"; -import { navigate } from "../../../navigation"; import { withInjectables } from "@ogre-tools/injectable-react"; import createResourceTabStoreInjectable from "./store.injectable"; import createResourceTemplatesInjectable from "./create-resource-templates.injectable"; import { Spinner } from "../../spinner"; import type { GroupBase } from "react-select"; +import type { Navigate } from "../../../navigation/navigate.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 navigateInjectable from "../../../navigation/navigate.injectable"; export interface CreateResourceProps { tab: DockTab; @@ -34,6 +37,9 @@ export interface CreateResourceProps { interface Dependencies { createResourceTemplates: IComputedValue[]>; createResourceTabStore: CreateResourceTabStore; + apiManager: ApiManager; + navigate: Navigate; + getDetailsUrl: GetDetailsUrl; } @observer @@ -63,6 +69,8 @@ class NonInjectedCreateResource extends React.Component => { + const { apiManager, getDetailsUrl, navigate } = this.props; + if (this.error || !this.data?.trim()) { // do not save when field is empty or there is an error return; @@ -155,8 +163,11 @@ export const CreateResource = withInjectables getPlaceholder: () => , getProps: async (di, props) => ({ + ...props, createResourceTabStore: di.inject(createResourceTabStoreInjectable), createResourceTemplates: await di.inject(createResourceTemplatesInjectable), - ...props, + apiManager: di.inject(apiManagerInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), + navigate: di.inject(navigateInjectable), }), }); diff --git a/src/renderer/components/kube-object-meta/kube-object-meta.tsx b/src/renderer/components/kube-object-meta/kube-object-meta.tsx index 54bac6388a..ff9c0f00d4 100644 --- a/src/renderer/components/kube-object-meta/kube-object-meta.tsx +++ b/src/renderer/components/kube-object-meta/kube-object-meta.tsx @@ -7,112 +7,126 @@ import React from "react"; import type { KubeMetaField } from "../../../common/k8s-api/kube-object"; import { KubeObject } from "../../../common/k8s-api/kube-object"; import { DrawerItem, DrawerItemLabels } from "../drawer"; -import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { ApiManager } from "../../../common/k8s-api/api-manager"; import { Link } from "react-router-dom"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { LocaleDate } from "../locale-date"; -import { getDetailsUrl } from "../kube-detail-params"; import logger from "../../../common/logger"; import { KubeObjectAge } from "../kube-object/age"; +import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable"; +import { observer } from "mobx-react"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable"; +import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable"; export interface KubeObjectMetaProps { object: KubeObject; hideFields?: KubeMetaField[]; } -export class KubeObjectMeta extends React.Component { - static defaultHiddenFields: KubeMetaField[] = [ - "uid", "resourceVersion", "selfLink", - ]; - - isHidden(field: KubeMetaField): boolean { - const { hideFields = KubeObjectMeta.defaultHiddenFields } = this.props; - - return hideFields.includes(field); - } - - render() { - const { object } = this.props; - - if (!object) { - return null; - } - - if (!(object instanceof KubeObject)) { - logger.error("[KubeObjectMeta]: passed object that is not an instanceof KubeObject", object); - - return null; - } - - const { - getNs, getLabels, getResourceVersion, selfLink, getAnnotations, - getFinalizers, getId, getName, metadata: { creationTimestamp }, - } = object; - const ownerRefs = object.getOwnerRefs(); - - return ( - <> - - - - - - -