diff --git a/src/common/k8s-api/endpoints/events.api.ts b/src/common/k8s-api/endpoints/events.api.ts index 8e6bc843b1..3a03c0ffbf 100644 --- a/src/common/k8s-api/endpoints/events.api.ts +++ b/src/common/k8s-api/endpoints/events.api.ts @@ -4,7 +4,7 @@ */ import moment from "moment"; -import type { KubeObjectMetadata, ObjectReference } from "../kube-object"; +import type { KubeObjectMetadata, KubeObjectScope, ObjectReference } from "../kube-object"; import { KubeObject } from "../kube-object"; import { formatDuration } from "../../utils/formatDuration"; import type { DerivedKubeApiOptions } from "../kube-api"; @@ -21,7 +21,7 @@ export interface EventSource { host?: string; } -export interface KubeEventData extends KubeJsonApiData { +export interface KubeEventData extends KubeJsonApiData, void, void> { action?: string; count?: number; eventTime?: string; @@ -38,7 +38,7 @@ export interface KubeEventData extends KubeJsonApiData, void, void> { static kind = "Event"; static namespaced = true; static apiBase = "/api/v1/events"; diff --git a/src/features/helm-charts/upgrade-chart/__snapshots__/upgrade-chart-new-tab.test.ts.snap b/src/features/helm-charts/upgrade-chart/__snapshots__/upgrade-chart-new-tab.test.ts.snap index 52d08559d6..fb8d74e570 100644 --- a/src/features/helm-charts/upgrade-chart/__snapshots__/upgrade-chart-new-tab.test.ts.snap +++ b/src/features/helm-charts/upgrade-chart/__snapshots__/upgrade-chart-new-tab.test.ts.snap @@ -1295,7 +1295,11 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
- my-second-namespace + + my-second-namespace +
- my-second-namespace + + my-second-namespace +
- my-second-namespace + + my-second-namespace +
- my-second-namespace + + my-second-namespace +
- my-second-namespace + + my-second-namespace +
- my-second-namespace + + my-second-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
- some-namespace + + some-namespace +
- some-other-namespace + + some-other-namespace +
{ getTargets(hpa: HorizontalPodAutoscaler) { const metrics = hpa.getMetrics(); @@ -54,7 +63,7 @@ export class HorizontalPodAutoscalers extends React.Component { isConfigurable tableId="configuration_hpa" className="HorizontalPodAutoscalers" - store={horizontalPodAutoscalerStore} + store={this.props.horizontalPodAutoscalerStore} sortingCallbacks={{ [columnId.name]: hpa => hpa.getName(), [columnId.namespace]: hpa => hpa.getNs(), @@ -81,7 +90,13 @@ export class HorizontalPodAutoscalers extends React.Component { renderTableContents={hpa => [ hpa.getName(), , - hpa.getNs(), + this.props.filterByNamespace(hpa.getNs()))} + > + {hpa.getNs()} + , this.getTargets(hpa), hpa.getMinPods(), hpa.getMaxPods(), @@ -105,3 +120,11 @@ export class HorizontalPodAutoscalers extends React.Component { ); } } + +export const HorizontalPodAutoscalers = withInjectables(NonInjectedHorizontalPodAutoscalers, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + horizontalPodAutoscalerStore: di.inject(horizontalPodAutoscalerStoreInjectable), + }), +}); diff --git a/src/renderer/components/+config-autoscalers/legacy-store.ts b/src/renderer/components/+config-autoscalers/legacy-store.ts deleted file mode 100644 index 87ff91360e..0000000000 --- a/src/renderer/components/+config-autoscalers/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import horizontalPodAutoscalerStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(horizontalPodAutoscalerStoreInjectable)` instead - */ -export const horizontalPodAutoscalerStore = asLegacyGlobalForExtensionApi(horizontalPodAutoscalerStoreInjectable); diff --git a/src/renderer/components/+config-leases/leases.scss b/src/renderer/components/+config-leases/leases.scss index ab7cbce494..f40556550e 100644 --- a/src/renderer/components/+config-leases/leases.scss +++ b/src/renderer/components/+config-leases/leases.scss @@ -20,5 +20,9 @@ &.age { flex: .5; } + + a.filterNamespace { + border-bottom: unset; + } } -} \ No newline at end of file +} diff --git a/src/renderer/components/+config-leases/leases.tsx b/src/renderer/components/+config-leases/leases.tsx index 1c665762ad..6c3025c077 100644 --- a/src/renderer/components/+config-leases/leases.tsx +++ b/src/renderer/components/+config-leases/leases.tsx @@ -13,10 +13,12 @@ import type { KubeObjectDetailsProps } from "../kube-object-details"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; -import { autoBind } from "../../../common/utils"; import { withInjectables } from "@ogre-tools/injectable-react"; import leaseStoreInjectable from "./store.injectable"; import type { LeaseStore } from "./store"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -30,15 +32,11 @@ export interface LeaseProps extends KubeObjectDetailsProps { interface Dependencies { leaseStore: LeaseStore; + filterByNamespace: FilterByNamespace; } @observer class NonInjectedLease extends React.Component { - constructor(props: LeaseProps & Dependencies) { - super(props); - autoBind(this); - } - render() { const { leaseStore } = this.props; @@ -69,7 +67,13 @@ class NonInjectedLease extends React.Component { renderTableContents={lease => [ lease.getName(), , - lease.getNs(), + this.props.filterByNamespace(lease.getNs()))} + > + {lease.getNs()} + , lease.getHolderIdentity(), , ]} @@ -83,5 +87,6 @@ export const Leases = withInjectables(NonInjectedLease getProps: (di, props) => ({ ...props, leaseStore: di.inject(leaseStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), }), }); diff --git a/src/renderer/components/+config-limit-ranges/legacy-store.ts b/src/renderer/components/+config-limit-ranges/legacy-store.ts deleted file mode 100644 index d3227c26c2..0000000000 --- a/src/renderer/components/+config-limit-ranges/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import limitRangeStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(limitRangeStoreInjectable)` instead - */ -export const limitRangeStore = asLegacyGlobalForExtensionApi(limitRangeStoreInjectable); diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.scss b/src/renderer/components/+config-limit-ranges/limit-ranges.scss index a795502173..1e26724d5c 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.scss +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.scss @@ -9,4 +9,8 @@ @include table-cell-warning; } } + + a.filterNamespace { + border-bottom: unset; + } } diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx index 3d233fe67a..ed189ed184 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx @@ -7,11 +7,16 @@ import "./limit-ranges.scss"; import { observer } from "mobx-react"; import { KubeObjectListLayout } from "../kube-object-list-layout"; -import { limitRangeStore } from "./legacy-store"; import React from "react"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import type { LimitRangeStore } from "./store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import limitRangeStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -19,8 +24,13 @@ enum columnId { age = "age", } +interface Dependencies { + filterByNamespace: FilterByNamespace; + limitRangeStore: LimitRangeStore; +} + @observer -export class LimitRanges extends React.Component { +class NonInjectedLimitRanges extends React.Component { render() { return ( @@ -28,7 +38,7 @@ export class LimitRanges extends React.Component { isConfigurable tableId="configuration_limitranges" className="LimitRanges" - store={limitRangeStore} + store={this.props.limitRangeStore} sortingCallbacks={{ [columnId.name]: limitRange => limitRange.getName(), [columnId.namespace]: limitRange => limitRange.getNs(), @@ -48,7 +58,13 @@ export class LimitRanges extends React.Component { renderTableContents={limitRange => [ limitRange.getName(), , - limitRange.getNs(), + this.props.filterByNamespace(limitRange.getNs()))} + > + {limitRange.getNs()} + , , ]} /> @@ -56,3 +72,11 @@ export class LimitRanges extends React.Component { ); } } + +export const LimitRanges = withInjectables(NonInjectedLimitRanges, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + limitRangeStore: di.inject(limitRangeStoreInjectable), + }), +}); diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index 1b7c88eed4..36c479ad99 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -9,24 +9,36 @@ import React from "react"; import { autorun, makeObservable, observable } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerTitle } from "../drawer"; -import { Notifications } from "../notifications"; +import type { ShowNotification } from "../notifications"; import { Input } from "../input"; import { Button } from "../button"; -import { configMapStore } from "./legacy-store"; import type { KubeObjectDetailsProps } from "../kube-object-details"; import { ConfigMap } from "../../../common/k8s-api/endpoints"; import { KubeObjectMeta } from "../kube-object-meta"; -import logger from "../../../common/logger"; +import type { Logger } from "../../../common/logger"; +import type { ConfigMapStore } from "./store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import configMapStoreInjectable from "./store.injectable"; +import showSuccessNotificationInjectable from "../notifications/show-success-notification.injectable"; +import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable"; +import loggerInjectable from "../../../common/logger.injectable"; export interface ConfigMapDetailsProps extends KubeObjectDetailsProps { } +interface Dependencies { + configMapStore: ConfigMapStore; + logger: Logger; + showSuccessNotification: ShowNotification; + showErrorNotification: ShowNotification; +} + @observer -export class ConfigMapDetails extends React.Component { +class NonInjectedConfigMapDetails extends React.Component { @observable isSaving = false; @observable data = observable.map(); - constructor(props: ConfigMapDetailsProps) { + constructor(props: ConfigMapDetailsProps & Dependencies) { super(props); makeObservable(this); } @@ -44,7 +56,7 @@ export class ConfigMapDetails extends React.Component { } save = async () => { - const { object: configMap } = this.props; + const { object: configMap, configMapStore } = this.props; try { this.isSaving = true; @@ -52,7 +64,7 @@ export class ConfigMapDetails extends React.Component { ...configMap, data: Object.fromEntries(this.data), }); - Notifications.ok(( + this.props.showSuccessNotification((

{"ConfigMap "} {configMap.getName()} @@ -60,14 +72,14 @@ export class ConfigMapDetails extends React.Component {

)); } catch (error) { - Notifications.error(`Failed to save config map: ${error}`); + this.props.showErrorNotification(`Failed to save config map: ${error}`); } finally { this.isSaving = false; } }; render() { - const { object: configMap } = this.props; + const { object: configMap, logger } = this.props; if (!configMap) { return null; @@ -118,3 +130,13 @@ export class ConfigMapDetails extends React.Component { ); } } + +export const ConfigMapDetails = withInjectables(NonInjectedConfigMapDetails, { + getProps: (di, props) => ({ + ...props, + configMapStore: di.inject(configMapStoreInjectable), + showSuccessNotification: di.inject(showSuccessNotificationInjectable), + showErrorNotification: di.inject(showErrorNotificationInjectable), + logger: di.inject(loggerInjectable), + }), +}); diff --git a/src/renderer/components/+config-maps/config-maps.scss b/src/renderer/components/+config-maps/config-maps.scss index e936512c42..7f8fd61f5c 100644 --- a/src/renderer/components/+config-maps/config-maps.scss +++ b/src/renderer/components/+config-maps/config-maps.scss @@ -20,5 +20,9 @@ &.age { flex: .5; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index ccfcc48962..212e8020e0 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -7,11 +7,16 @@ import "./config-maps.scss"; import React from "react"; import { observer } from "mobx-react"; -import { configMapStore } from "./legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { prevDefault } from "../../utils"; +import type { ConfigMapStore } from "./store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import configMapStoreInjectable from "./store.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -20,8 +25,13 @@ enum columnId { age = "age", } +interface Dependencies { + configMapStore: ConfigMapStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class ConfigMaps extends React.Component { +class NonInjectedConfigMaps extends React.Component { render() { return ( @@ -29,7 +39,7 @@ export class ConfigMaps extends React.Component { isConfigurable tableId="configuration_configmaps" className="ConfigMaps" - store={configMapStore} + store={this.props.configMapStore} sortingCallbacks={{ [columnId.name]: configMap => configMap.getName(), [columnId.namespace]: configMap => configMap.getNs(), @@ -51,7 +61,13 @@ export class ConfigMaps extends React.Component { renderTableContents={configMap => [ configMap.getName(), , - configMap.getNs(), + this.props.filterByNamespace(configMap.getNs()))} + > + {configMap.getNs()} + , configMap.getKeys().join(", "), , ]} @@ -60,3 +76,11 @@ export class ConfigMaps extends React.Component { ); } } + +export const ConfigMaps = withInjectables(NonInjectedConfigMaps, { + getProps: (di, props) => ({ + ...props, + configMapStore: di.inject(configMapStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + }), +}); diff --git a/src/renderer/components/+config-maps/legacy-store.ts b/src/renderer/components/+config-maps/legacy-store.ts deleted file mode 100644 index d655de6d1c..0000000000 --- a/src/renderer/components/+config-maps/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import configMapStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(configMapStoreInjectable)` instead - */ -export const configMapStore = asLegacyGlobalForExtensionApi(configMapStoreInjectable); diff --git a/src/renderer/components/+config-pod-disruption-budgets/legacy-store.ts b/src/renderer/components/+config-pod-disruption-budgets/legacy-store.ts deleted file mode 100644 index 4e0f2ec7d1..0000000000 --- a/src/renderer/components/+config-pod-disruption-budgets/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import podDisruptionBudgetStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(podDisruptionBudgetStoreInjectable)` instead - */ -export const podDisruptionBudgetStore = asLegacyGlobalForExtensionApi(podDisruptionBudgetStoreInjectable); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.scss b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.scss index c58e89fe43..99f8fedec6 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.scss +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.scss @@ -20,5 +20,9 @@ &.age { flex: .5; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx index ff9fe884a1..f2cfa76090 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx @@ -7,13 +7,18 @@ import "./pod-disruption-budgets.scss"; import * as React from "react"; import { observer } from "mobx-react"; -import { podDisruptionBudgetStore } from "./legacy-store"; import type { PodDisruptionBudget } from "../../../common/k8s-api/endpoints/pod-disruption-budget.api"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { KubeObjectDetailsProps } from "../kube-object-details"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import type { PodDisruptionBudgetStore } from "./store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import podDisruptionBudgetStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -28,8 +33,13 @@ enum columnId { export interface PodDisruptionBudgetsProps extends KubeObjectDetailsProps { } +interface Dependencies { + filterByNamespace: FilterByNamespace; + podDisruptionBudgetStore: PodDisruptionBudgetStore; +} + @observer -export class PodDisruptionBudgets extends React.Component { +class NonInjectedPodDisruptionBudgets extends React.Component { render() { return ( @@ -37,7 +47,7 @@ export class PodDisruptionBudgets extends React.Component pdb.getName(), [columnId.namespace]: pdb => pdb.getNs(), @@ -64,7 +74,13 @@ export class PodDisruptionBudgets extends React.Component [ pdb.getName(), , - pdb.getNs(), + this.props.filterByNamespace(pdb.getNs()))} + > + {pdb.getNs()} + , pdb.getMinAvailable(), pdb.getMaxUnavailable(), pdb.getCurrentHealthy(), @@ -76,3 +92,11 @@ export class PodDisruptionBudgets extends React.Component(NonInjectedPodDisruptionBudgets, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + podDisruptionBudgetStore: di.inject(podDisruptionBudgetStoreInjectable), + }), +}); diff --git a/src/renderer/components/+config-resource-quotas/legacy-store.ts b/src/renderer/components/+config-resource-quotas/legacy-store.ts deleted file mode 100644 index 2f13765856..0000000000 --- a/src/renderer/components/+config-resource-quotas/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import resourceQuotaStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(resourceQuotaStoreInjectable)` instead - */ -export const resourceQuotaStore = asLegacyGlobalForExtensionApi(resourceQuotaStoreInjectable); diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.scss b/src/renderer/components/+config-resource-quotas/resource-quotas.scss index 154d5d429a..5cfef82e92 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.scss +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.scss @@ -8,5 +8,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index 607274ee0f..06cba945ad 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -9,10 +9,15 @@ import React from "react"; import { observer } from "mobx-react"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { AddQuotaDialog } from "./add-quota-dialog"; -import { resourceQuotaStore } from "./legacy-store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { prevDefault } from "../../utils"; +import type { ResourceQuotaStore } from "./store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import resourceQuotaStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -20,8 +25,13 @@ enum columnId { age = "age", } +interface Dependencies { + resourceQuotaStore: ResourceQuotaStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class ResourceQuotas extends React.Component { +class NonInjectedResourceQuotas extends React.Component { render() { return ( @@ -29,7 +39,7 @@ export class ResourceQuotas extends React.Component { isConfigurable tableId="configuration_quotas" className="ResourceQuotas" - store={resourceQuotaStore} + store={this.props.resourceQuotaStore} sortingCallbacks={{ [columnId.name]: resourceQuota => resourceQuota.getName(), [columnId.namespace]: resourceQuota => resourceQuota.getNs(), @@ -49,7 +59,13 @@ export class ResourceQuotas extends React.Component { renderTableContents={resourceQuota => [ resourceQuota.getName(), , - resourceQuota.getNs(), + this.props.filterByNamespace(resourceQuota.getNs()))} + > + {resourceQuota.getNs()} + , , ]} addRemoveButtons={{ @@ -62,3 +78,11 @@ export class ResourceQuotas extends React.Component { ); } } + +export const ResourceQuotas = withInjectables(NonInjectedResourceQuotas, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + resourceQuotaStore: di.inject(resourceQuotaStoreInjectable), + }), +}); diff --git a/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx b/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx index dd4044014c..f1e3aad2b4 100644 --- a/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx +++ b/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx @@ -8,6 +8,7 @@ import { SecretDetails } from "../secret-details"; import { Secret, SecretType } from "../../../../common/k8s-api/endpoints"; import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; import { renderFor } from "../../test-utils/renderFor"; +import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable"; jest.mock("../../kube-object-meta/kube-object-meta", () => ({ KubeObjectMeta: () => null, @@ -18,6 +19,8 @@ describe("SecretDetails tests", () => { const di = getDiForUnitTesting({ doGeneralOverrides: true }); const render = renderFor(di); + di.override(storesAndApisCanBeCreatedInjectable, () => true); + const secret = new Secret({ apiVersion: "v1", kind: "secret", diff --git a/src/renderer/components/+config-secrets/legacy-store.ts b/src/renderer/components/+config-secrets/legacy-store.ts deleted file mode 100644 index f6ab0be80e..0000000000 --- a/src/renderer/components/+config-secrets/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import secretStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(secretStoreInjectable)` instead - */ -export const secretStore = asLegacyGlobalForExtensionApi(secretStoreInjectable); diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index 2176b7c1ce..c22f7befe8 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -11,25 +11,38 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Input } from "../input"; import { Button } from "../button"; -import { Notifications } from "../notifications"; +import type { ShowNotification } from "../notifications"; import { base64, toggle } from "../../utils"; import { Icon } from "../icon"; -import { secretStore } from "./legacy-store"; import type { KubeObjectDetailsProps } from "../kube-object-details"; import { Secret } from "../../../common/k8s-api/endpoints"; import { KubeObjectMeta } from "../kube-object-meta"; -import logger from "../../../common/logger"; +import type { Logger } from "../../../common/logger"; +import type { SecretStore } from "./store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import loggerInjectable from "../../../common/logger.injectable"; +import secretStoreInjectable from "./store.injectable"; +import showSuccessNotificationInjectable from "../notifications/show-success-notification.injectable"; +import type { ShowCheckedErrorNotification } from "../notifications/show-checked-error.injectable"; +import showCheckedErrorNotificationInjectable from "../notifications/show-checked-error.injectable"; export interface SecretDetailsProps extends KubeObjectDetailsProps { } +interface Dependencies { + secretStore: SecretStore; + logger: Logger; + showSuccessNotification: ShowNotification; + showCheckedErrorNotification: ShowCheckedErrorNotification; +} + @observer -export class SecretDetails extends React.Component { +class NonInjectedSecretDetails extends React.Component { @observable isSaving = false; @observable data: Partial> = {}; @observable revealSecret = observable.set(); - constructor(props: SecretDetailsProps) { + constructor(props: SecretDetailsProps & Dependencies) { super(props); makeObservable(this); } @@ -53,10 +66,10 @@ export class SecretDetails extends React.Component { this.isSaving = true; try { - await secretStore.update(secret, { ...secret, data: this.data }); - Notifications.ok("Secret successfully updated."); + await this.props.secretStore.update(secret, { ...secret, data: this.data }); + this.props.showSuccessNotification("Secret successfully updated."); } catch (err) { - Notifications.checkedError(err, "Unknown error occured while updating the secret"); + this.props.showCheckedErrorNotification(err, "Unknown error occured while updating the secret"); } this.isSaving = false; }; @@ -134,7 +147,7 @@ export class SecretDetails extends React.Component { } render() { - const { object: secret } = this.props; + const { object: secret, logger } = this.props; if (!secret) { return null; @@ -157,3 +170,13 @@ export class SecretDetails extends React.Component { ); } } + +export const SecretDetails = withInjectables(NonInjectedSecretDetails, { + getProps: (di, props) => ({ + ...props, + logger: di.inject(loggerInjectable), + secretStore: di.inject(secretStoreInjectable), + showCheckedErrorNotification: di.inject(showCheckedErrorNotificationInjectable), + showSuccessNotification: di.inject(showSuccessNotificationInjectable), + }), +}); diff --git a/src/renderer/components/+config-secrets/secrets.scss b/src/renderer/components/+config-secrets/secrets.scss index 65422772e9..41dd4ca709 100644 --- a/src/renderer/components/+config-secrets/secrets.scss +++ b/src/renderer/components/+config-secrets/secrets.scss @@ -16,5 +16,9 @@ &.labels { @include table-cell-labels-offsets; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index 6cac97afc3..eda3269fd0 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -10,10 +10,15 @@ import { observer } from "mobx-react"; import { AddSecretDialog } from "./add-secret-dialog"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { Badge } from "../badge"; -import { secretStore } from "./legacy-store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import type { SecretStore } from "./store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import secretStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -24,8 +29,13 @@ enum columnId { age = "age", } +interface Dependencies { + filterByNamespace: FilterByNamespace; + secretStore: SecretStore; +} + @observer -export class Secrets extends React.Component { +class NonInjectedSecrets extends React.Component { render() { return ( @@ -33,7 +43,7 @@ export class Secrets extends React.Component { isConfigurable tableId="configuration_secrets" className="Secrets" - store={secretStore} + store={this.props.secretStore} sortingCallbacks={{ [columnId.name]: secret => secret.getName(), [columnId.namespace]: secret => secret.getNs(), @@ -59,7 +69,13 @@ export class Secrets extends React.Component { renderTableContents={secret => [ secret.getName(), , - secret.getNs(), + this.props.filterByNamespace(secret.getNs()))} + > + {secret.getNs()} + , secret.getLabels().map(label => ( (NonInjectedSecrets, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + secretStore: di.inject(secretStoreInjectable), + }), +}); diff --git a/src/renderer/components/+custom-resources/crd-resources.scss b/src/renderer/components/+custom-resources/crd-resources.scss index 1402036c53..3b217a77bf 100644 --- a/src/renderer/components/+custom-resources/crd-resources.scss +++ b/src/renderer/components/+custom-resources/crd-resources.scss @@ -4,5 +4,7 @@ */ .CrdResources { - + a.filterNamespace { + border-bottom: unset; + } } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index ca8884bcd3..51ecd656ae 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -19,6 +19,9 @@ import { KubeObjectAge } from "../kube-object/age"; import type { CustomResourceDefinitionStore } from "./definition.store"; import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable"; import customResourceDefinitionStoreInjectable from "./definition.store.injectable"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -31,6 +34,7 @@ interface Dependencies { name: IComputedValue; apiManager: ApiManager; customResourceDefinitionStore: CustomResourceDefinitionStore; + filterByNamespace: FilterByNamespace; } @observer @@ -102,7 +106,15 @@ class NonInjectedCustomResources extends React.Component { ]} renderTableContents={customResource => [ customResource.getName(), - isNamespaced && customResource.getNs(), + isNamespaced && ( + this.props.filterByNamespace(customResource.getNs() as string))} + > + {customResource.getNs()} + + ), ...extraColumns.map((column) => safeJSONPathValue(customResource, column.jsonPath)), , ]} @@ -129,6 +141,7 @@ export const CustomResources = withInjectables(NonInjectedCustomRe ...di.inject(customResourcesRouteParametersInjectable), apiManager: di.inject(apiManagerInjectable), customResourceDefinitionStore: di.inject(customResourceDefinitionStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), }), }); diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index 0a2c713415..e1b9e57bb8 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -19,9 +19,8 @@ import type { HeaderCustomizer } from "../item-object-list"; import { Tooltip } from "../tooltip"; import { Link } from "react-router-dom"; import type { IClassName } from "../../utils"; -import { cssNames, stopPropagation } from "../../utils"; +import { prevDefault, cssNames, stopPropagation } from "../../utils"; import { Icon } from "../icon"; -import { getDetailsUrl } from "../kube-detail-params"; import type { ApiManager } from "../../../common/k8s-api/api-manager"; import { withInjectables } from "@ogre-tools/injectable-react"; import navigateToEventsInjectable from "../../../common/front-end-routing/routes/cluster/events/navigate-to-events.injectable"; @@ -29,6 +28,10 @@ import { KubeObjectAge } from "../kube-object/age"; import { ReactiveDuration } from "../duration/reactive-duration"; import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable"; import eventStoreInjectable from "./store.injectable"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable"; +import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable"; enum columnId { message = "message", @@ -55,6 +58,8 @@ interface Dependencies { navigateToEvents: () => void; eventStore: EventStore; apiManager: ApiManager; + filterByNamespace: FilterByNamespace; + getDetailsUrl: GetDetailsUrl; } @observer @@ -196,10 +201,20 @@ class NonInjectedEvents extends React.Component { ), }, - event.getNs(), + compact + ? ( + this.props.filterByNamespace(event.getNs()))} + > + {event.getNs()} + + ) + : event.getNs(), {`${involvedObject.kind}: ${involvedObject.name}`} @@ -231,5 +246,7 @@ export const Events = withInjectables(NonInjectedEven navigateToEvents: di.inject(navigateToEventsInjectable), apiManager: di.inject(apiManagerInjectable), eventStore: di.inject(eventStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), }), }); diff --git a/src/renderer/components/+helm-releases/releases.scss b/src/renderer/components/+helm-releases/releases.scss index 589bd37541..04955a60eb 100644 --- a/src/renderer/components/+helm-releases/releases.scss +++ b/src/renderer/components/+helm-releases/releases.scss @@ -20,5 +20,9 @@ } } } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+helm-releases/releases.tsx b/src/renderer/components/+helm-releases/releases.tsx index 7b5fd99dac..5714c92fd1 100644 --- a/src/renderer/components/+helm-releases/releases.tsx +++ b/src/renderer/components/+helm-releases/releases.tsx @@ -9,7 +9,6 @@ import "./releases.scss"; import React, { Component } from "react"; import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { withInjectables } from "@ogre-tools/injectable-react"; -import namespaceStoreInjectable from "../+namespaces/store.injectable"; import type { ItemListStore } from "../item-object-list"; import { ItemListLayout } from "../item-object-list"; import { NamespaceSelectFilter } from "../+namespaces/namespace-select-filter"; @@ -24,6 +23,9 @@ import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import helmReleasesRouteParametersInjectable from "./helm-releases-route-parameters.injectable"; 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 { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -39,9 +41,9 @@ enum columnId { interface Dependencies { releases: IComputedValue; releasesArePending: IComputedValue; - selectNamespace: (namespace: string) => void; namespace: IComputedValue; navigateToHelmReleases: NavigateToHelmReleases; + filterByNamespace: FilterByNamespace; } class NonInjectedHelmReleases extends Component { @@ -50,7 +52,7 @@ class NonInjectedHelmReleases extends Component { const namespace = this.props.namespace.get(); if (namespace) { - this.props.selectNamespace(namespace); + this.props.filterByNamespace(namespace); } } @@ -186,7 +188,13 @@ class NonInjectedHelmReleases extends Component { ]} renderTableContents={release => [ release.getName(), - release.getNs(), + this.props.filterByNamespace(release.getNs()))} + > + {release.getNs()} + , release.getChart(), release.getRevision(), release.getVersion(), @@ -213,20 +221,12 @@ class NonInjectedHelmReleases extends Component { } } -export const HelmReleases = withInjectables( - NonInjectedHelmReleases, - - { - getProps: (di) => { - const routeParameters = di.inject(helmReleasesRouteParametersInjectable); - - return { - releases: di.inject(removableReleasesInjectable), - releasesArePending: di.inject(releasesInjectable).pending, - selectNamespace: di.inject(namespaceStoreInjectable).selectNamespaces, - navigateToHelmReleases: di.inject(navigateToHelmReleasesInjectable), - namespace: routeParameters.namespace, - }; - }, - }, -); +export const HelmReleases = withInjectables(NonInjectedHelmReleases, { + getProps: (di) => ({ + releases: di.inject(removableReleasesInjectable), + releasesArePending: di.inject(releasesInjectable).pending, + navigateToHelmReleases: di.inject(navigateToHelmReleasesInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + ...di.inject(helmReleasesRouteParametersInjectable), + }), +}); diff --git a/src/renderer/components/+namespaces/namespace-select-filter-model/filter-by-namespace.injectable.ts b/src/renderer/components/+namespaces/namespace-select-filter-model/filter-by-namespace.injectable.ts new file mode 100644 index 0000000000..fff1c37202 --- /dev/null +++ b/src/renderer/components/+namespaces/namespace-select-filter-model/filter-by-namespace.injectable.ts @@ -0,0 +1,19 @@ +/** + * 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 namespaceStoreInjectable from "../store.injectable"; + +export type FilterByNamespace = (namespace: string) => void; + +const filterByNamespaceInjectable = getInjectable({ + id: "filter-by-namespace", + instantiate: (di): FilterByNamespace => { + const namespaceStore = di.inject(namespaceStoreInjectable); + + return (namespace) => namespaceStore.selectSingle(namespace); + }, +}); + +export default filterByNamespaceInjectable; diff --git a/src/renderer/components/+network-endpoints/endpoints.scss b/src/renderer/components/+network-endpoints/endpoints.scss index 0f5b29213f..a79d36ff17 100644 --- a/src/renderer/components/+network-endpoints/endpoints.scss +++ b/src/renderer/components/+network-endpoints/endpoints.scss @@ -12,5 +12,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index d97c2be98b..4358906a67 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -7,11 +7,16 @@ import "./endpoints.scss"; import React from "react"; import { observer } from "mobx-react"; -import { endpointsStore } from "./legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { prevDefault } from "../../utils"; +import type { EndpointsStore } from "./store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import endpointsStoreInjectable from "./store.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -20,8 +25,13 @@ enum columnId { age = "age", } +interface Dependencies { + endpointsStore: EndpointsStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class Endpoints extends React.Component { +class NonInjectedEndpoints extends React.Component { render() { return ( @@ -29,7 +39,7 @@ export class Endpoints extends React.Component { isConfigurable tableId="network_endpoints" className="Endpoints" - store={endpointsStore} + store={this.props.endpointsStore} sortingCallbacks={{ [columnId.name]: endpoint => endpoint.getName(), [columnId.namespace]: endpoint => endpoint.getNs(), @@ -49,7 +59,13 @@ export class Endpoints extends React.Component { renderTableContents={endpoint => [ endpoint.getName(), , - endpoint.getNs(), + this.props.filterByNamespace(endpoint.getNs()))} + > + {endpoint.getNs()} + , endpoint.toString(), , ]} @@ -65,3 +81,11 @@ export class Endpoints extends React.Component { ); } } + +export const Endpoints = withInjectables(NonInjectedEndpoints, { + getProps: (di, props) => ({ + ...props, + endpointsStore: di.inject(endpointsStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + }), +}); diff --git a/src/renderer/components/+network-endpoints/legacy-store.ts b/src/renderer/components/+network-endpoints/legacy-store.ts deleted file mode 100644 index f66d144619..0000000000 --- a/src/renderer/components/+network-endpoints/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import endpointsStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(endpointsStoreInjectable)` - */ -export const endpointsStore = asLegacyGlobalForExtensionApi(endpointsStoreInjectable); diff --git a/src/renderer/components/+network-ingresses/ingresses.scss b/src/renderer/components/+network-ingresses/ingresses.scss index 960ba3702f..fdf0bda6b8 100644 --- a/src/renderer/components/+network-ingresses/ingresses.scss +++ b/src/renderer/components/+network-ingresses/ingresses.scss @@ -31,5 +31,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index 1ca8589f80..a8403e142b 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -7,12 +7,17 @@ import "./ingresses.scss"; import React from "react"; import { observer } from "mobx-react"; -import { ingressStore } from "./legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; import { computeRouteDeclarations } from "../../../common/k8s-api/endpoints"; +import { prevDefault } from "../../utils"; +import type { IngressStore } from "./store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import ingressStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -22,8 +27,13 @@ enum columnId { age = "age", } +interface Dependencies { + ingressStore: IngressStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class Ingresses extends React.Component { +class NonInjectedIngresses extends React.Component { render() { return ( @@ -31,7 +41,7 @@ export class Ingresses extends React.Component { isConfigurable tableId="network_ingresses" className="Ingresses" - store={ingressStore} + store={this.props.ingressStore} sortingCallbacks={{ [columnId.name]: ingress => ingress.getName(), [columnId.namespace]: ingress => ingress.getNs(), @@ -53,7 +63,13 @@ export class Ingresses extends React.Component { renderTableContents={ingress => [ ingress.getName(), , - ingress.getNs(), + this.props.filterByNamespace(ingress.getNs()))} + > + {ingress.getNs()} + , ingress.getLoadBalancers().map(lb =>

{lb}

), computeRouteDeclarations(ingress).map(decl => ( decl.displayAsLink @@ -90,3 +106,11 @@ export class Ingresses extends React.Component { ); } } + +export const Ingresses = withInjectables(NonInjectedIngresses, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + ingressStore: di.inject(ingressStoreInjectable), + }), +}); diff --git a/src/renderer/components/+network-ingresses/legacy-store.ts b/src/renderer/components/+network-ingresses/legacy-store.ts deleted file mode 100644 index 0731109f5d..0000000000 --- a/src/renderer/components/+network-ingresses/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import ingressStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(ingressStoreInjectable)` instead - */ -export const ingressStore = asLegacyGlobalForExtensionApi(ingressStoreInjectable); diff --git a/src/renderer/components/+network-policies/legacy-store.ts b/src/renderer/components/+network-policies/legacy-store.ts deleted file mode 100644 index b8da3f6081..0000000000 --- a/src/renderer/components/+network-policies/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import networkPolicyStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(networkPolicyStoreInjectable)` instead - */ -export const networkPolicyStore = asLegacyGlobalForExtensionApi(networkPolicyStoreInjectable); diff --git a/src/renderer/components/+network-policies/network-policies.scss b/src/renderer/components/+network-policies/network-policies.scss index 6b0c3c1920..d9170a4cb4 100644 --- a/src/renderer/components/+network-policies/network-policies.scss +++ b/src/renderer/components/+network-policies/network-policies.scss @@ -8,5 +8,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index 88b1425802..a4aeac21f7 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -8,10 +8,15 @@ import "./network-policies.scss"; import React from "react"; import { observer } from "mobx-react"; import { KubeObjectListLayout } from "../kube-object-list-layout"; -import { networkPolicyStore } from "./legacy-store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import type { NetworkPolicyStore } from "./store"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import networkPolicyStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -20,8 +25,13 @@ enum columnId { age = "age", } +interface Dependencies { + networkPolicyStore: NetworkPolicyStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class NetworkPolicies extends React.Component { +class NonInjectedNetworkPolicies extends React.Component { render() { return ( @@ -29,7 +39,7 @@ export class NetworkPolicies extends React.Component { isConfigurable tableId="network_policies" className="NetworkPolicies" - store={networkPolicyStore} + store={this.props.networkPolicyStore} sortingCallbacks={{ [columnId.name]: networkPolicy => networkPolicy.getName(), [columnId.namespace]: networkPolicy => networkPolicy.getNs(), @@ -49,7 +59,13 @@ export class NetworkPolicies extends React.Component { renderTableContents={networkPolicy => [ networkPolicy.getName(), , - networkPolicy.getNs(), + this.props.filterByNamespace(networkPolicy.getNs()))} + > + {networkPolicy.getNs()} + , networkPolicy.getTypes().join(", "), , ]} @@ -58,3 +74,11 @@ export class NetworkPolicies extends React.Component { ); } } + +export const NetworkPolicies = withInjectables(NonInjectedNetworkPolicies, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + networkPolicyStore: di.inject(networkPolicyStoreInjectable), + }), +}); diff --git a/src/renderer/components/+network-port-forwards/port-forwards.scss b/src/renderer/components/+network-port-forwards/port-forwards.scss index d9518987e3..ede9873736 100644 --- a/src/renderer/components/+network-port-forwards/port-forwards.scss +++ b/src/renderer/components/+network-port-forwards/port-forwards.scss @@ -13,5 +13,9 @@ @include port-forward-status-colors; flex: 0.6; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+network-port-forwards/port-forwards.tsx b/src/renderer/components/+network-port-forwards/port-forwards.tsx index fc6b4c4735..8010bf9545 100644 --- a/src/renderer/components/+network-port-forwards/port-forwards.tsx +++ b/src/renderer/components/+network-port-forwards/port-forwards.tsx @@ -19,6 +19,9 @@ import { computed, makeObservable } from "mobx"; import portForwardsRouteParametersInjectable from "./port-forwards-route-parameters.injectable"; import type { NavigateToPortForwards } from "../../../common/front-end-routing/routes/cluster/network/port-forwards/navigate-to-port-forwards.injectable"; import navigateToPortForwardsInjectable from "../../../common/front-end-routing/routes/cluster/network/port-forwards/navigate-to-port-forwards.injectable"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -34,6 +37,7 @@ interface Dependencies { portForwardStore: PortForwardStore; forwardport: IComputedValue; navigateToPortForwards: NavigateToPortForwards; + filterByNamespace: FilterByNamespace; } @observer @@ -128,7 +132,13 @@ class NonInjectedPortForwards extends React.Component { ]} renderTableContents={item => [ item.getName(), - item.getNs(), + this.props.filterByNamespace(item.getNs()))} + > + {item.getNs()} + , item.getKind(), item.getPort(), item.getForwardPort(), @@ -158,19 +168,12 @@ class NonInjectedPortForwards extends React.Component { } } -export const PortForwards = withInjectables( - NonInjectedPortForwards, - - { - getProps: (di) => { - const routeParameters = di.inject(portForwardsRouteParametersInjectable); - - return { - portForwardStore: di.inject(portForwardStoreInjectable), - forwardport: routeParameters.forwardport, - navigateToPortForwards: di.inject(navigateToPortForwardsInjectable), - }; - }, - }, -); +export const PortForwards = withInjectables(NonInjectedPortForwards, { + getProps: (di) => ({ + portForwardStore: di.inject(portForwardStoreInjectable), + ...di.inject(portForwardsRouteParametersInjectable), + navigateToPortForwards: di.inject(navigateToPortForwardsInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + }), +}); diff --git a/src/renderer/components/+network-services/legacy-store.ts b/src/renderer/components/+network-services/legacy-store.ts deleted file mode 100644 index 507136ef3e..0000000000 --- a/src/renderer/components/+network-services/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import serviceStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(serviceStoreInjectable)` instead - */ -export const serviceStore = asLegacyGlobalForExtensionApi(serviceStoreInjectable); diff --git a/src/renderer/components/+network-services/service-details-endpoint.tsx b/src/renderer/components/+network-services/service-details-endpoint.tsx index 8d1e0f6166..f7dec5077a 100644 --- a/src/renderer/components/+network-services/service-details-endpoint.tsx +++ b/src/renderer/components/+network-services/service-details-endpoint.tsx @@ -7,31 +7,33 @@ import { observer } from "mobx-react"; import React from "react"; import { Table, TableHead, TableCell, TableRow } from "../table"; import { prevDefault } from "../../utils"; -import { endpointsStore } from "../+network-endpoints/legacy-store"; -import { Spinner } from "../spinner"; -import { showDetails } from "../kube-detail-params"; -import logger from "../../../common/logger"; +import type { Logger } from "../../../common/logger"; import { Endpoints } from "../../../common/k8s-api/endpoints"; +import type { ShowDetails } from "../kube-detail-params/show-details.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import loggerInjectable from "../../../common/logger.injectable"; +import showDetailsInjectable from "../kube-detail-params/show-details.injectable"; export interface ServiceDetailsEndpointProps { endpoints: Endpoints; } +interface Dependencies { + logger: Logger; + showDetails: ShowDetails; +} + @observer -export class ServiceDetailsEndpoint extends React.Component { +class NonInjectedServiceDetailsEndpoint extends React.Component { render() { const { endpoints } = this.props; - if (!endpoints && !endpointsStore.isLoaded) return ( -
- ); - if (!endpoints) { return null; } if (!(endpoints instanceof Endpoints)) { - logger.error("[ServiceDetailsEndpoint]: passed object that is not an instanceof Endpoints", endpoints); + this.props.logger.error("[ServiceDetailsEndpoint]: passed object that is not an instanceof Endpoints", endpoints); return null; } @@ -51,7 +53,7 @@ export class ServiceDetailsEndpoint extends React.Component showDetails(endpoints.selfLink, false))} + onClick={prevDefault(() => this.props.showDetails(endpoints.selfLink, false))} > {endpoints.getName()} { endpoints.toString()} @@ -61,3 +63,11 @@ export class ServiceDetailsEndpoint extends React.Component(NonInjectedServiceDetailsEndpoint, { + getProps: (di, props) => ({ + ...props, + logger: di.inject(loggerInjectable), + showDetails: di.inject(showDetailsInjectable), + }), +}); diff --git a/src/renderer/components/+network-services/services.scss b/src/renderer/components/+network-services/services.scss index 64bc038f2b..5136582cf0 100644 --- a/src/renderer/components/+network-services/services.scss +++ b/src/renderer/components/+network-services/services.scss @@ -25,5 +25,9 @@ @include service-status-colors; flex: 0.6; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index bc43eb1539..17295b0af8 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -9,10 +9,16 @@ import React from "react"; import { observer } from "mobx-react"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { Badge } from "../badge"; -import { serviceStore } from "./legacy-store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import { prevDefault } from "../../utils"; +import type { ServiceStore } from "./store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import type { Service } from "../../../common/k8s-api/endpoints"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import serviceStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -26,8 +32,27 @@ enum columnId { status = "status", } +const formatExternalIps = (service: Service) => { + const externalIps = service.getExternalIps(); + + if (externalIps.length > 0) { + return externalIps.join(", "); + } + + if (service.spec?.externalName) { + return service.spec.externalName; + } + + return "-"; +}; + +interface Dependencies { + serviceStore: ServiceStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class Services extends React.Component { +class NonInjectedServices extends React.Component { render() { return ( @@ -35,7 +60,7 @@ export class Services extends React.Component { isConfigurable tableId="network_services" className="Services" - store={serviceStore} + store={this.props.serviceStore} sortingCallbacks={{ [columnId.name]: service => service.getName(), [columnId.namespace]: service => service.getNs(), @@ -64,28 +89,34 @@ export class Services extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} - renderTableContents={service => { - const externalIps = service.getExternalIps(); - - if (externalIps.length === 0 && service.spec?.externalName) { - externalIps.push(service.spec.externalName); - } - - return [ - service.getName(), - , - service.getNs(), - service.getType(), - service.getClusterIp(), - service.getPorts().join(", "), - externalIps.join(", ") || "-", - service.getSelector().map(label => ), - , - { title: service.getStatus(), className: service.getStatus().toLowerCase() }, - ]; - }} + renderTableContents={service => [ + service.getName(), + , + this.props.filterByNamespace(service.getNs())) } + > + { service.getNs() } + , + service.getType(), + service.getClusterIp(), + service.getPorts().join(", "), + formatExternalIps(service), + service.getSelector().map(label => ), + , + { title: service.getStatus(), className: service.getStatus().toLowerCase() }, + ]} /> ); } } + +export const Services = withInjectables(NonInjectedServices, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + serviceStore: di.inject(serviceStoreInjectable), + }), +}); diff --git a/src/renderer/components/+storage-volume-claims/legacy-store.ts b/src/renderer/components/+storage-volume-claims/legacy-store.ts deleted file mode 100644 index ec63bef14d..0000000000 --- a/src/renderer/components/+storage-volume-claims/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import persistentVolumeClaimStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(persistentVolumeClaimStoreInjectable)` instead - */ -export const persistentVolumeClaimStore = asLegacyGlobalForExtensionApi(persistentVolumeClaimStoreInjectable); diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.scss b/src/renderer/components/+storage-volume-claims/volume-claims.scss index d42d57ce8b..ac476c595c 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.scss +++ b/src/renderer/components/+storage-volume-claims/volume-claims.scss @@ -38,5 +38,9 @@ &.age { flex: 0.4; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index b1c615314b..31ebee4bc4 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -8,16 +8,23 @@ import "./volume-claims.scss"; import React from "react"; import { observer } from "mobx-react"; import { Link } from "react-router-dom"; -import { persistentVolumeClaimStore } from "./legacy-store"; -import { podStore } from "../+workloads-pods/legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { unitsToBytes } from "../../../common/utils/convertMemory"; -import { stopPropagation } from "../../utils"; -import { storageClassApi } from "../../../common/k8s-api/endpoints"; +import { prevDefault, stopPropagation } from "../../utils"; +import type { StorageClassApi } from "../../../common/k8s-api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; -import { getDetailsUrl } from "../kube-detail-params"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import type { PersistentVolumeClaimStore } from "./store"; +import type { PodStore } from "../+workloads-pods/store"; +import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable"; +import persistentVolumeClaimStoreInjectable from "./store.injectable"; +import podStoreInjectable from "../+workloads-pods/store.injectable"; +import storageClassApiInjectable from "../../../common/k8s-api/endpoints/storage-class.api.injectable"; enum columnId { name = "name", @@ -29,9 +36,25 @@ enum columnId { age = "age", } +interface Dependencies { + persistentVolumeClaimStore: PersistentVolumeClaimStore; + storageClassApi: StorageClassApi; + podStore: PodStore; + getDetailsUrl: GetDetailsUrl; + filterByNamespace: FilterByNamespace; +} + @observer -export class PersistentVolumeClaims extends React.Component { +class NonInjectedPersistentVolumeClaims extends React.Component { render() { + const { + persistentVolumeClaimStore, + filterByNamespace, + getDetailsUrl, + podStore, + storageClassApi, + } = this.props; + return ( { const pods = pvc.getPods(podStore.items); const { storageClassName } = pvc.spec; - const storageClassDetailsUrl = getDetailsUrl(storageClassApi.getUrl({ + const storageClassDetailsUrl = getDetailsUrl(storageClassApi.formatUrlForNotListing({ name: storageClassName, })); return [ pvc.getName(), , - pvc.getNs(), + filterByNamespace(pvc.getNs()))} + > + {pvc.getNs()} + , (NonInjectedPersistentVolumeClaims, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + getDetailsUrl: di.inject(getDetailsUrlInjectable), + persistentVolumeClaimStore: di.inject(persistentVolumeClaimStoreInjectable), + podStore: di.inject(podStoreInjectable), + storageClassApi: di.inject(storageClassApiInjectable), + }), +}); diff --git a/src/renderer/components/+user-management/+cluster-roles/store.injectable.ts b/src/renderer/components/+user-management/+cluster-roles/store.injectable.ts index 021dd23d6e..bfd83f3b3b 100644 --- a/src/renderer/components/+user-management/+cluster-roles/store.injectable.ts +++ b/src/renderer/components/+user-management/+cluster-roles/store.injectable.ts @@ -7,7 +7,7 @@ import assert from "assert"; import { storesAndApisCanBeCreatedInjectionToken } from "../../../../common/k8s-api/stores-apis-can-be-created.token"; import clusterRoleApiInjectable from "../../../../common/k8s-api/endpoints/cluster-role.api.injectable"; import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable"; -import { ClusterRolesStore } from "./store"; +import { ClusterRoleStore } from "./store"; const clusterRoleStoreInjectable = getInjectable({ id: "cluster-role-store", @@ -16,7 +16,7 @@ const clusterRoleStoreInjectable = getInjectable({ const api = di.inject(clusterRoleApiInjectable); - return new ClusterRolesStore(api); + return new ClusterRoleStore(api); }, injectionToken: kubeObjectStoreInjectionToken, }); diff --git a/src/renderer/components/+user-management/+cluster-roles/store.ts b/src/renderer/components/+user-management/+cluster-roles/store.ts index 9d680285e8..a8df8bdb90 100644 --- a/src/renderer/components/+user-management/+cluster-roles/store.ts +++ b/src/renderer/components/+user-management/+cluster-roles/store.ts @@ -5,7 +5,7 @@ import type { ClusterRole, ClusterRoleApi, ClusterRoleData } from "../../../../common/k8s-api/endpoints"; import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store"; -export class ClusterRolesStore extends KubeObjectStore { +export class ClusterRoleStore extends KubeObjectStore { protected sortItems(items: ClusterRole[]) { return super.sortItems(items, [ clusterRole => clusterRole.kind, diff --git a/src/renderer/components/+user-management/+role-bindings/view.scss b/src/renderer/components/+user-management/+role-bindings/view.scss index 032561422c..d57c5679c3 100644 --- a/src/renderer/components/+user-management/+role-bindings/view.scss +++ b/src/renderer/components/+user-management/+role-bindings/view.scss @@ -12,5 +12,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+user-management/+role-bindings/view.tsx b/src/renderer/components/+user-management/+role-bindings/view.tsx index ef2447cf5f..58afc14a5e 100644 --- a/src/renderer/components/+user-management/+role-bindings/view.tsx +++ b/src/renderer/components/+user-management/+role-bindings/view.tsx @@ -9,12 +9,20 @@ import React from "react"; import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { RoleBindingDialog } from "./dialog"; -import { roleBindingStore } from "./legacy-store"; -import { roleStore } from "../+roles/legacy-store"; -import { clusterRoleStore } from "../+cluster-roles/legacy-store"; -import { serviceAccountStore } from "../+service-accounts/legacy-store"; import { SiblingsInTabLayout } from "../../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../../kube-object/age"; +import type { RoleStore } from "../+roles/store"; +import type { ServiceAccountStore } from "../+service-accounts/store"; +import type { RoleBindingStore } from "./store"; +import { prevDefault } from "../../../utils"; +import type { ClusterRoleStore } from "../+cluster-roles/store"; +import type { FilterByNamespace } from "../../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import clusterRoleStoreInjectable from "../+cluster-roles/store.injectable"; +import filterByNamespaceInjectable from "../../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import roleBindingStoreInjectable from "./store.injectable"; +import roleStoreInjectable from "../+roles/store.injectable"; +import serviceAccountStoreInjectable from "../+service-accounts/store.injectable"; enum columnId { name = "name", @@ -23,9 +31,25 @@ enum columnId { age = "age", } +interface Dependencies { + roleBindingStore: RoleBindingStore; + roleStore: RoleStore; + clusterRoleStore: ClusterRoleStore; + serviceAccountStore: ServiceAccountStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class RoleBindings extends React.Component { +class NonInjectedRoleBindings extends React.Component { render() { + const { + clusterRoleStore, + roleBindingStore, + roleStore, + serviceAccountStore, + filterByNamespace, + } = this.props; + return ( [ binding.getName(), , - binding.getNs(), + filterByNamespace(binding.getNs()))} + > + {binding.getNs()} + , binding.getSubjectNames(), , ]} @@ -69,3 +99,14 @@ export class RoleBindings extends React.Component { ); } } + +export const RoleBindings = withInjectables(NonInjectedRoleBindings, { + getProps: (di, props) => ({ + ...props, + clusterRoleStore: di.inject(clusterRoleStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + roleBindingStore: di.inject(roleBindingStoreInjectable), + roleStore: di.inject(roleStoreInjectable), + serviceAccountStore: di.inject(serviceAccountStoreInjectable), + }), +}); diff --git a/src/renderer/components/+user-management/+roles/view.scss b/src/renderer/components/+user-management/+roles/view.scss index 690aa3d8b0..7ed72f8cc2 100644 --- a/src/renderer/components/+user-management/+roles/view.scss +++ b/src/renderer/components/+user-management/+roles/view.scss @@ -12,5 +12,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+user-management/+roles/view.tsx b/src/renderer/components/+user-management/+roles/view.tsx index c67f630919..35b9bdc0d8 100644 --- a/src/renderer/components/+user-management/+roles/view.tsx +++ b/src/renderer/components/+user-management/+roles/view.tsx @@ -10,9 +10,14 @@ import React from "react"; import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { AddRoleDialog } from "./add-dialog"; -import { roleStore } from "./legacy-store"; import { SiblingsInTabLayout } from "../../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../../kube-object/age"; +import type { RoleStore } from "./store"; +import { prevDefault } from "../../../utils"; +import type { FilterByNamespace } from "../../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import roleStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -20,9 +25,19 @@ enum columnId { age = "age", } +interface Dependencies { + roleStore: RoleStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class Roles extends React.Component { +class NonInjectedRoles extends React.Component { render() { + const { + filterByNamespace, + roleStore, + } = this.props; + return ( [ role.getName(), , - role.getNs(), + filterByNamespace(role.getNs()))} + > + {role.getNs()} + , , ]} addRemoveButtons={{ @@ -61,3 +82,11 @@ export class Roles extends React.Component { ); } } + +export const Roles = withInjectables(NonInjectedRoles, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + roleStore: di.inject(roleStoreInjectable), + }), +}); diff --git a/src/renderer/components/+user-management/+service-accounts/details.tsx b/src/renderer/components/+user-management/+service-accounts/details.tsx index 03ba9c0029..788be09e54 100644 --- a/src/renderer/components/+user-management/+service-accounts/details.tsx +++ b/src/renderer/components/+user-management/+service-accounts/details.tsx @@ -10,7 +10,6 @@ import { disposeOnUnmount, observer } from "mobx-react"; import React from "react"; import { Link } from "react-router-dom"; -import { secretStore } from "../../+config-secrets/legacy-store"; import type { Secret, ServiceAccount } from "../../../../common/k8s-api/endpoints"; import { DrawerItem, DrawerTitle } from "../../drawer"; import { Icon } from "../../icon"; @@ -18,23 +17,32 @@ import type { KubeObjectDetailsProps } from "../../kube-object-details"; import { KubeObjectMeta } from "../../kube-object-meta"; import { Spinner } from "../../spinner"; import { ServiceAccountsSecret } from "./secret"; -import { getDetailsUrl } from "../../kube-detail-params"; +import type { SecretStore } from "../../+config-secrets/store"; +import type { GetDetailsUrl } from "../../kube-detail-params/get-details-url.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable"; +import secretStoreInjectable from "../../+config-secrets/store.injectable"; export interface ServiceAccountsDetailsProps extends KubeObjectDetailsProps { } -const defensiveLoadSecretIn = (namespace: string) => ( - ({ name }: { name: string }) => ( - secretStore.load({ name, namespace }) - .catch(() => name) - ) -); +interface Dependencies { + secretStore: SecretStore; + getDetailsUrl: GetDetailsUrl; +} @observer -export class ServiceAccountsDetails extends React.Component { +class NonInjectedServiceAccountsDetails extends React.Component { readonly secrets = observable.array(); readonly imagePullSecrets = observable.array(); + private defensiveLoadSecretIn = (namespace: string) => ( + ({ name }: { name: string }) => ( + this.props.secretStore.load({ name, namespace }) + .catch(() => name) + ) + ); + componentDidMount(): void { disposeOnUnmount(this, [ autorun(async () => { @@ -50,7 +58,7 @@ export class ServiceAccountsDetails extends React.Component + {secret.getName()} ); @@ -116,7 +124,7 @@ export class ServiceAccountsDetails extends React.Component(NonInjectedServiceAccountsDetails, { + getProps: (di, props) => ({ + ...props, + getDetailsUrl: di.inject(getDetailsUrlInjectable), + secretStore: di.inject(secretStoreInjectable), + }), +}); diff --git a/src/renderer/components/+user-management/+service-accounts/view.scss b/src/renderer/components/+user-management/+service-accounts/view.scss index 6147c1e117..e1fa133b5e 100644 --- a/src/renderer/components/+user-management/+service-accounts/view.scss +++ b/src/renderer/components/+user-management/+service-accounts/view.scss @@ -8,5 +8,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+user-management/+service-accounts/view.tsx b/src/renderer/components/+user-management/+service-accounts/view.tsx index 610c3cc20d..68161112f8 100644 --- a/src/renderer/components/+user-management/+service-accounts/view.tsx +++ b/src/renderer/components/+user-management/+service-accounts/view.tsx @@ -10,9 +10,14 @@ import React from "react"; import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { CreateServiceAccountDialog } from "./create-dialog"; -import { serviceAccountStore } from "./legacy-store"; import { SiblingsInTabLayout } from "../../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../../kube-object/age"; +import { prevDefault } from "../../../utils"; +import type { ServiceAccountStore } from "./store"; +import type { FilterByNamespace } from "../../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import filterByNamespaceInjectable from "../../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import serviceAccountStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -20,9 +25,19 @@ enum columnId { age = "age", } +interface Dependencies { + serviceAccountStore: ServiceAccountStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class ServiceAccounts extends React.Component { +class NonInjectedServiceAccounts extends React.Component { render() { + const { + filterByNamespace, + serviceAccountStore, + } = this.props; + return ( [ account.getName(), , - account.getNs(), + filterByNamespace(account.getNs()))} + > + {account.getNs()} + , , ]} addRemoveButtons={{ @@ -62,3 +83,10 @@ export class ServiceAccounts extends React.Component { } } +export const ServiceAccounts = withInjectables(NonInjectedServiceAccounts, { + getProps: (di, props) => ({ + ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), + serviceAccountStore: di.inject(serviceAccountStoreInjectable), + }), +}); diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.scss b/src/renderer/components/+workloads-cronjobs/cronjobs.scss index 0302a45d45..29b9fb18c1 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.scss +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.scss @@ -8,5 +8,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index 24eff99303..10d51efb33 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -19,6 +19,9 @@ import { withInjectables } from "@ogre-tools/injectable-react"; import cronJobStoreInjectable from "./store.injectable"; import jobStoreInjectable from "../+workloads-jobs/store.injectable"; import eventStoreInjectable from "../+events/store.injectable"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -34,6 +37,7 @@ interface Dependencies { cronJobStore: CronJobStore; jobStore: JobStore; eventStore: EventStore; + filterByNamespace: FilterByNamespace; } @observer @@ -43,6 +47,7 @@ class NonInjectedCronJobs extends React.Component{ cronJobStore, eventStore, jobStore, + filterByNamespace, } = this.props; return ( @@ -83,7 +88,13 @@ class NonInjectedCronJobs extends React.Component{ renderTableContents={cronJob => [ cronJob.getName(), , - cronJob.getNs(), + filterByNamespace(cronJob.getNs()))} + > + {cronJob.getNs()} + , cronJob.isNeverRun() ? "never" : cronJob.getSchedule(), cronJob.getSuspendFlag(), cronJobStore.getActiveJobsNum(cronJob), @@ -98,9 +109,10 @@ class NonInjectedCronJobs extends React.Component{ export const CronJobs = withInjectables(NonInjectedCronJobs, { getProps: (di, props) => ({ + ...props, cronJobStore: di.inject(cronJobStoreInjectable), eventStore: di.inject(eventStoreInjectable), jobStore: di.inject(jobStoreInjectable), - ...props, + filterByNamespace: di.inject(filterByNamespaceInjectable), }), }); diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.scss b/src/renderer/components/+workloads-daemonsets/daemonsets.scss index 9c0a9e386c..1500c74d78 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.scss +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.scss @@ -21,5 +21,9 @@ flex-grow: 1.5; @include table-cell-labels-offsets; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx index bd3610c541..795acb59b2 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx @@ -8,14 +8,21 @@ import "./daemonsets.scss"; import React from "react"; import { observer } from "mobx-react"; import type { DaemonSet } from "../../../common/k8s-api/endpoints"; -import { eventStore } from "../+events/legacy-store"; -import { daemonSetStore } from "./legacy-store"; -import { podStore } from "../+workloads-pods/legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { Badge } from "../badge"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import type { DaemonSetStore } from "./store"; +import type { PodStore } from "../+workloads-pods/store"; +import type { EventStore } from "../+events/store"; +import { prevDefault } from "../../utils"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import daemonSetStoreInjectable from "./store.injectable"; +import eventStoreInjectable from "../+events/store.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import podStoreInjectable from "../+workloads-pods/store.injectable"; enum columnId { name = "name", @@ -25,13 +32,27 @@ enum columnId { age = "age", } +interface Dependencies { + daemonSetStore: DaemonSetStore; + podStore: PodStore; + eventStore: EventStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class DaemonSets extends React.Component { +class NonInjectedDaemonSets extends React.Component { getPodsLength(daemonSet: DaemonSet) { - return daemonSetStore.getChildPods(daemonSet).length; + return this.props.daemonSetStore.getChildPods(daemonSet).length; } render() { + const { + daemonSetStore, + eventStore, + filterByNamespace, + podStore, + } = this.props; + return ( [ daemonSet.getName(), - daemonSet.getNs(), + filterByNamespace(daemonSet.getNs()))} + > + {daemonSet.getNs()} + , this.getPodsLength(daemonSet), , daemonSet.getNodeSelectors().map(selector => ( @@ -78,3 +105,13 @@ export class DaemonSets extends React.Component { ); } } + +export const DaemonSets = withInjectables(NonInjectedDaemonSets, { + getProps: (di, props) => ({ + ...props, + daemonSetStore: di.inject(daemonSetStoreInjectable), + eventStore: di.inject(eventStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + podStore: di.inject(podStoreInjectable), + }), +}); diff --git a/src/renderer/components/+workloads-daemonsets/legacy-store.ts b/src/renderer/components/+workloads-daemonsets/legacy-store.ts deleted file mode 100644 index afd40e7df2..0000000000 --- a/src/renderer/components/+workloads-daemonsets/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import daemonSetStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(daemonSetStoreInjectable)` instead - */ -export const daemonSetStore = asLegacyGlobalForExtensionApi(daemonSetStoreInjectable); diff --git a/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx index fdc2bdf804..1f73e176db 100644 --- a/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx @@ -15,9 +15,12 @@ import { prevDefault, stopPropagation } from "../../utils"; import { DrawerTitle } from "../drawer"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; -import { replicaSetStore } from "../+workloads-replicasets/legacy-store"; -import { showDetails } from "../kube-detail-params"; import { KubeObjectAge } from "../kube-object/age"; +import type { ReplicaSetStore } from "../+workloads-replicasets/store"; +import type { ShowDetails } from "../kube-detail-params/show-details.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import showDetailsInjectable from "../kube-detail-params/show-details.injectable"; +import replicaSetStoreInjectable from "../+workloads-replicasets/store.injectable"; enum sortBy { @@ -31,14 +34,23 @@ export interface DeploymentReplicaSetsProps { replicaSets: ReplicaSet[]; } +interface Dependencies { + replicaSetStore: ReplicaSetStore; + showDetails: ShowDetails; +} + @observer -export class DeploymentReplicaSets extends React.Component { +class NonInjectedDeploymentReplicaSets extends React.Component { getPodsLength(replicaSet: ReplicaSet) { - return replicaSetStore.getChildPods(replicaSet).length; + return this.props.replicaSetStore.getChildPods(replicaSet).length; } render() { - const { replicaSets } = this.props; + const { + replicaSets, + replicaSetStore, + showDetails, + } = this.props; if (!replicaSets.length && !replicaSetStore.isLoaded) return (
@@ -95,6 +107,14 @@ export class DeploymentReplicaSets extends React.Component(NonInjectedDeploymentReplicaSets, { + getProps: (di, props) => ({ + ...props, + replicaSetStore: di.inject(replicaSetStoreInjectable), + showDetails: di.inject(showDetailsInjectable), + }), +}); + export function ReplicaSetMenu(props: KubeObjectMenuProps) { return ( diff --git a/src/renderer/components/+workloads-deployments/deployments.scss b/src/renderer/components/+workloads-deployments/deployments.scss index a1a1ac856f..322faa6d8d 100644 --- a/src/renderer/components/+workloads-deployments/deployments.scss +++ b/src/renderer/components/+workloads-deployments/deployments.scss @@ -42,5 +42,9 @@ } } } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index cc6f2a88c5..d069cd73c1 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -8,15 +8,20 @@ import "./deployments.scss"; import React from "react"; import { observer } from "mobx-react"; import type { Deployment } from "../../../common/k8s-api/endpoints"; -import { deploymentStore } from "./legacy-store"; -import { eventStore } from "../+events/legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; -import { cssNames } from "../../utils"; +import { cssNames, prevDefault } from "../../utils"; import kebabCase from "lodash/kebabCase"; import orderBy from "lodash/orderBy"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import type { DeploymentStore } from "./store"; +import type { EventStore } from "../+events/store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import deploymentStoreInjectable from "./store.injectable"; +import eventStoreInjectable from "../+events/store.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -27,8 +32,14 @@ enum columnId { condition = "condition", } +interface Dependencies { + deploymentStore: DeploymentStore; + eventStore: EventStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class Deployments extends React.Component { +class NonInjectedDeployments extends React.Component { renderPods(deployment: Deployment) { const { replicas, availableReplicas } = deployment.status ?? {}; @@ -50,6 +61,12 @@ export class Deployments extends React.Component { } render() { + const { + deploymentStore, + eventStore, + filterByNamespace, + } = this.props; + return ( [ deployment.getName(), , - deployment.getNs(), + filterByNamespace(deployment.getNs()))} + > + {deployment.getNs()} + , this.renderPods(deployment), deployment.getReplicas(), , @@ -93,3 +116,12 @@ export class Deployments extends React.Component { ); } } + +export const Deployments = withInjectables(NonInjectedDeployments, { + getProps: (di, props) => ({ + ...props, + deploymentStore: di.inject(deploymentStoreInjectable), + eventStore: di.inject(eventStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + }), +}); diff --git a/src/renderer/components/+workloads-deployments/legacy-store.ts b/src/renderer/components/+workloads-deployments/legacy-store.ts deleted file mode 100644 index f7d629729b..0000000000 --- a/src/renderer/components/+workloads-deployments/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import deploymentStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(deploymentStoreInjectable)` instead - */ -export const deploymentStore = asLegacyGlobalForExtensionApi(deploymentStoreInjectable); diff --git a/src/renderer/components/+workloads-jobs/jobs.scss b/src/renderer/components/+workloads-jobs/jobs.scss index c19dd6c467..a24cfc7b06 100644 --- a/src/renderer/components/+workloads-jobs/jobs.scss +++ b/src/renderer/components/+workloads-jobs/jobs.scss @@ -18,5 +18,9 @@ &.conditions { @include job-condition-colors; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index 2d6f559c73..f1455bd2f8 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -7,13 +7,19 @@ import "./jobs.scss"; import React from "react"; import { observer } from "mobx-react"; -import { jobStore } from "./legacy-store"; -import { eventStore } from "../+events/legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import kebabCase from "lodash/kebabCase"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import type { JobStore } from "./store"; +import type { EventStore } from "../+events/store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { prevDefault } from "../../utils"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import eventStoreInjectable from "../+events/store.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import jobStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -23,9 +29,21 @@ enum columnId { age = "age", } +interface Dependencies { + jobStore: JobStore; + eventStore: EventStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class Jobs extends React.Component { +class NonInjectedJobs extends React.Component { render() { + const { + eventStore, + filterByNamespace, + jobStore, + } = this.props; + return ( filterByNamespace(job.getNs()))} + > + {job.getNs()} + , `${job.getCompletions()} / ${job.getDesiredCompletions()}`, , , @@ -72,3 +96,12 @@ export class Jobs extends React.Component { ); } } + +export const Jobs = withInjectables(NonInjectedJobs, { + getProps: (di, props) => ({ + ...props, + eventStore: di.inject(eventStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + jobStore: di.inject(jobStoreInjectable), + }), +}); diff --git a/src/renderer/components/+workloads-jobs/legacy-store.ts b/src/renderer/components/+workloads-jobs/legacy-store.ts deleted file mode 100644 index b4b7e47f85..0000000000 --- a/src/renderer/components/+workloads-jobs/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import jobStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(jobStoreInjectable)` instead - */ -export const jobStore = asLegacyGlobalForExtensionApi(jobStoreInjectable); diff --git a/src/renderer/components/+workloads-pods/pods.scss b/src/renderer/components/+workloads-pods/pods.scss index 9a6ad8c8ab..ee606bc762 100644 --- a/src/renderer/components/+workloads-pods/pods.scss +++ b/src/renderer/components/+workloads-pods/pods.scss @@ -37,5 +37,9 @@ @include pod-status-colors; flex-grow: 0.7; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index 147353f6d6..2e55562154 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -11,7 +11,7 @@ import { Link } from "react-router-dom"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import type { NodeApi, Pod } from "../../../common/k8s-api/endpoints"; import { StatusBrick } from "../status-brick"; -import { cssNames, getConvertedParts, object, stopPropagation } from "../../utils"; +import { cssNames, getConvertedParts, object, prevDefault, stopPropagation } from "../../utils"; import startCase from "lodash/startCase"; import kebabCase from "lodash/kebabCase"; import type { ApiManager } from "../../../common/k8s-api/api-manager"; @@ -28,6 +28,8 @@ 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"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; enum columnId { name = "name", @@ -43,6 +45,7 @@ enum columnId { interface Dependencies { getDetailsUrl: GetDetailsUrl; + filterByNamespace: FilterByNamespace; apiManager: ApiManager; eventStore: EventStore; podStore: PodStore; @@ -149,7 +152,13 @@ class NonInjectedPods extends React.Component { expandable={false} />, , - pod.getNs(), + this.props.filterByNamespace(pod.getNs()))} + > + {pod.getNs()} + , this.renderContainersStatus(pod), pod.getRestartsCount(), pod.getOwnerRefs().map(ref => { @@ -201,5 +210,6 @@ export const Pods = withInjectables(NonInjectedPods, { nodeApi: di.inject(nodeApiInjectable), eventStore: di.inject(eventStoreInjectable), podStore: di.inject(podStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), }), }); diff --git a/src/renderer/components/+workloads-replicasets/legacy-store.ts b/src/renderer/components/+workloads-replicasets/legacy-store.ts deleted file mode 100644 index ac835163d4..0000000000 --- a/src/renderer/components/+workloads-replicasets/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import replicaSetStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(replicaSetStoreInjectable)` instead - */ -export const replicaSetStore = asLegacyGlobalForExtensionApi(replicaSetStoreInjectable); diff --git a/src/renderer/components/+workloads-replicasets/replicasets.scss b/src/renderer/components/+workloads-replicasets/replicasets.scss index 4b213bda92..07e70c53c1 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.scss +++ b/src/renderer/components/+workloads-replicasets/replicasets.scss @@ -12,5 +12,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index 43f2c78184..277072d2fa 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -7,12 +7,18 @@ import "./replicasets.scss"; import React from "react"; import { observer } from "mobx-react"; -import { replicaSetStore } from "./legacy-store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { KubeObjectListLayout } from "../kube-object-list-layout"; -import { eventStore } from "../+events/legacy-store"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import type { ReplicaSetStore } from "./store"; +import type { EventStore } from "../+events/store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { prevDefault } from "../../utils"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import eventStoreInjectable from "../+events/store.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import replicaSetStoreInjectable from "./store.injectable"; enum columnId { name = "name", @@ -23,9 +29,21 @@ enum columnId { age = "age", } +interface Dependencies { + replicaSetStore: ReplicaSetStore; + eventStore: EventStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class ReplicaSets extends React.Component { +class NonInjectedReplicaSets extends React.Component { render() { + const { + eventStore, + filterByNamespace, + replicaSetStore, + } = this.props; + return ( [ replicaSet.getName(), , - replicaSet.getNs(), + filterByNamespace(replicaSet.getNs()))} + > + {replicaSet.getNs()} + , replicaSet.getDesired(), replicaSet.getCurrent(), replicaSet.getReady(), @@ -70,3 +94,11 @@ export class ReplicaSets extends React.Component { } } +export const ReplicaSets = withInjectables(NonInjectedReplicaSets, { + getProps: (di, props) => ({ + ...props, + eventStore: di.inject(eventStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + replicaSetStore: di.inject(replicaSetStoreInjectable), + }), +}); diff --git a/src/renderer/components/+workloads-statefulsets/legacy-store.ts b/src/renderer/components/+workloads-statefulsets/legacy-store.ts deleted file mode 100644 index b96347a78b..0000000000 --- a/src/renderer/components/+workloads-statefulsets/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import statefulSetStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(statefulSetStoreInjectable)` instead - */ -export const statefulSetStore = asLegacyGlobalForExtensionApi(statefulSetStoreInjectable); diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.scss b/src/renderer/components/+workloads-statefulsets/statefulsets.scss index 55d49f4b49..23b4da9242 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.scss +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.scss @@ -16,5 +16,9 @@ &.warning { @include table-cell-warning; } + + a.filterNamespace { + border-bottom: unset; + } } } diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index 0f849355a6..fb8d68702e 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -8,13 +8,20 @@ import "./statefulsets.scss"; import React from "react"; import { observer } from "mobx-react"; import type { StatefulSet } from "../../../common/k8s-api/endpoints"; -import { podStore } from "../+workloads-pods/legacy-store"; -import { statefulSetStore } from "./legacy-store"; -import { eventStore } from "../+events/legacy-store"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../kube-object/age"; +import type { StatefulSetStore } from "./store"; +import type { PodStore } from "../+workloads-pods/store"; +import type { EventStore } from "../+events/store"; +import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import eventStoreInjectable from "../+events/store.injectable"; +import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable"; +import podStoreInjectable from "../+workloads-pods/store.injectable"; +import statefulSetStoreInjectable from "./store.injectable"; +import { prevDefault } from "../../utils"; enum columnId { name = "name", @@ -24,8 +31,15 @@ enum columnId { replicas = "replicas", } +interface Dependencies { + statefulSetStore: StatefulSetStore; + podStore: PodStore; + eventStore: EventStore; + filterByNamespace: FilterByNamespace; +} + @observer -export class StatefulSets extends React.Component { +class NonInjectedStatefulSets extends React.Component { renderPods(statefulSet: StatefulSet) { const { readyReplicas, currentReplicas } = statefulSet.status ?? {}; @@ -33,6 +47,13 @@ export class StatefulSets extends React.Component { } render() { + const { + eventStore, + filterByNamespace, + podStore, + statefulSetStore, + } = this.props; + return ( [ statefulSet.getName(), - statefulSet.getNs(), + filterByNamespace(statefulSet.getNs()))} + > + {statefulSet.getNs()} + , this.renderPods(statefulSet), statefulSet.getReplicas(), , @@ -72,3 +99,13 @@ export class StatefulSets extends React.Component { ); } } + +export const StatefulSets = withInjectables(NonInjectedStatefulSets, { + getProps: (di, props) => ({ + ...props, + eventStore: di.inject(eventStoreInjectable), + filterByNamespace: di.inject(filterByNamespaceInjectable), + podStore: di.inject(podStoreInjectable), + statefulSetStore: di.inject(statefulSetStoreInjectable), + }), +}); diff --git a/src/renderer/components/test-utils/get-application-builder.tsx b/src/renderer/components/test-utils/get-application-builder.tsx index 575ea7b508..ee26baa163 100644 --- a/src/renderer/components/test-utils/get-application-builder.tsx +++ b/src/renderer/components/test-utils/get-application-builder.tsx @@ -499,6 +499,7 @@ export const getApplicationBuilder = () => { api: windowDi.inject(namespaceApiInjectable), items: namespaceItems, selectNamespaces: () => {}, + selectSingle: () => {}, getByPath: () => undefined, pickOnlySelected: () => [], isSelectedAll: () => false,