1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Add buttons to quicky filter the current view by a specific namespace (#6677)

* Add quick namespace filtering in pods view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to HorizontalPodAutoscalers view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Leases view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to LimitRanges view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to ConfigMaps view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove last usage of legacy global

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to PodDisruptionBudgets view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to ResourceQuotas view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Secrets view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove last usage of legacy global secretsStore

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to CustomResources view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Events view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to HelmReleases view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Endpoints view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove last usage of legacy global endpointsStore

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Ingresses view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to NetworkPolicies view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to PortForwards view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Services view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to PersistentVolumeClaims view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to RoleBindings view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Roles view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to ServiceAccounts view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to CronJobs view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to DaemonSets view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Deployments view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to Jobs view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to StatefulSets view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add quick namespace filtering to ReplicaSets view

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove last usage of legacy global replicaSetStore

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix up missing styles

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-12-01 06:20:56 -08:00 committed by GitHub
parent ab4a99bd93
commit a546f3b8ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 1184 additions and 433 deletions

View File

@ -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<KubeObjectMetadata, void, void> {
export interface KubeEventData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
action?: string;
count?: number;
eventTime?: string;
@ -38,7 +38,7 @@ export interface KubeEventData extends KubeJsonApiData<KubeObjectMetadata, void,
type?: string;
}
export class KubeEvent extends KubeObject {
export class KubeEvent extends KubeObject<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
static kind = "Event";
static namespaced = true;
static apiBase = "/api/v1/events";

View File

@ -1295,7 +1295,11 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
<div
class="TableCell namespace"
>
my-second-namespace
<a
class="filterNamespace"
>
my-second-namespace
</a>
</div>
<div
class="TableCell chart"
@ -2048,7 +2052,11 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
<div
class="TableCell namespace"
>
my-second-namespace
<a
class="filterNamespace"
>
my-second-namespace
</a>
</div>
<div
class="TableCell chart"
@ -2855,7 +2863,11 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
<div
class="TableCell namespace"
>
my-second-namespace
<a
class="filterNamespace"
>
my-second-namespace
</a>
</div>
<div
class="TableCell chart"
@ -3698,7 +3710,11 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
<div
class="TableCell namespace"
>
my-second-namespace
<a
class="filterNamespace"
>
my-second-namespace
</a>
</div>
<div
class="TableCell chart"
@ -4681,7 +4697,11 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
<div
class="TableCell namespace"
>
my-second-namespace
<a
class="filterNamespace"
>
my-second-namespace
</a>
</div>
<div
class="TableCell chart"
@ -5666,7 +5686,11 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
<div
class="TableCell namespace"
>
my-second-namespace
<a
class="filterNamespace"
>
my-second-namespace
</a>
</div>
<div
class="TableCell chart"

View File

@ -2122,7 +2122,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -2204,7 +2208,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -3038,7 +3046,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -3120,7 +3132,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -4015,7 +4031,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -4097,7 +4117,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -4992,7 +5016,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -5074,7 +5102,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -6214,7 +6246,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -6296,7 +6332,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -7436,7 +7476,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -7518,7 +7562,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -10754,7 +10802,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -10836,7 +10888,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -11976,7 +12032,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -12058,7 +12118,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -12953,7 +13017,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -13035,7 +13103,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -13933,7 +14005,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -14015,7 +14091,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -14849,7 +14929,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -14931,7 +15015,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"
@ -15826,7 +15914,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-namespace
<a
class="filterNamespace"
>
some-namespace
</a>
</div>
<div
class="TableCell chart"
@ -15908,7 +16000,11 @@ exports[`showing details for helm release given application is started when navi
<div
class="TableCell namespace"
>
some-other-namespace
<a
class="filterNamespace"
>
some-other-namespace
</a>
</div>
<div
class="TableCell chart"

View File

@ -9,12 +9,16 @@ import React from "react";
import { observer } from "mobx-react";
import { KubeObjectListLayout } from "../kube-object-list-layout";
import type { HorizontalPodAutoscaler } from "../../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api";
import { horizontalPodAutoscalerStore } from "./legacy-store";
import { Badge } from "../badge";
import { cssNames } from "../../utils";
import { cssNames, prevDefault } from "../../utils";
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
import { KubeObjectAge } from "../kube-object/age";
import type { HorizontalPodAutoscalerStore } 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 horizontalPodAutoscalerStoreInjectable from "./store.injectable";
enum columnId {
name = "name",
@ -27,8 +31,13 @@ enum columnId {
status = "status",
}
interface Dependencies {
horizontalPodAutoscalerStore: HorizontalPodAutoscalerStore;
filterByNamespace: FilterByNamespace;
}
@observer
export class HorizontalPodAutoscalers extends React.Component {
class NonInjectedHorizontalPodAutoscalers extends React.Component<Dependencies> {
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(),
<KubeObjectStatusIcon key="icon" object={hpa} />,
hpa.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(hpa.getNs()))}
>
{hpa.getNs()}
</a>,
this.getTargets(hpa),
hpa.getMinPods(),
hpa.getMaxPods(),
@ -105,3 +120,11 @@ export class HorizontalPodAutoscalers extends React.Component {
);
}
}
export const HorizontalPodAutoscalers = withInjectables<Dependencies>(NonInjectedHorizontalPodAutoscalers, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
horizontalPodAutoscalerStore: di.inject(horizontalPodAutoscalerStoreInjectable),
}),
});

View File

@ -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);

View File

@ -20,5 +20,9 @@
&.age {
flex: .5;
}
a.filterNamespace {
border-bottom: unset;
}
}
}
}

View File

@ -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<Lease> {
interface Dependencies {
leaseStore: LeaseStore;
filterByNamespace: FilterByNamespace;
}
@observer
class NonInjectedLease extends React.Component<LeaseProps & Dependencies> {
constructor(props: LeaseProps & Dependencies) {
super(props);
autoBind(this);
}
render() {
const { leaseStore } = this.props;
@ -69,7 +67,13 @@ class NonInjectedLease extends React.Component<LeaseProps & Dependencies> {
renderTableContents={lease => [
lease.getName(),
<KubeObjectStatusIcon key="icon" object={lease} />,
lease.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(lease.getNs()))}
>
{lease.getNs()}
</a>,
lease.getHolderIdentity(),
<KubeObjectAge key="age" object={lease} />,
]}
@ -83,5 +87,6 @@ export const Leases = withInjectables<Dependencies, LeaseProps>(NonInjectedLease
getProps: (di, props) => ({
...props,
leaseStore: di.inject(leaseStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -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);

View File

@ -9,4 +9,8 @@
@include table-cell-warning;
}
}
a.filterNamespace {
border-bottom: unset;
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={limitRange}/>,
limitRange.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(limitRange.getNs()))}
>
{limitRange.getNs()}
</a>,
<KubeObjectAge key="age" object={limitRange} />,
]}
/>
@ -56,3 +72,11 @@ export class LimitRanges extends React.Component {
);
}
}
export const LimitRanges = withInjectables<Dependencies>(NonInjectedLimitRanges, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
limitRangeStore: di.inject(limitRangeStoreInjectable),
}),
});

View File

@ -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<ConfigMap> {
}
interface Dependencies {
configMapStore: ConfigMapStore;
logger: Logger;
showSuccessNotification: ShowNotification;
showErrorNotification: ShowNotification;
}
@observer
export class ConfigMapDetails extends React.Component<ConfigMapDetailsProps> {
class NonInjectedConfigMapDetails extends React.Component<ConfigMapDetailsProps & Dependencies> {
@observable isSaving = false;
@observable data = observable.map<string, string | undefined>();
constructor(props: ConfigMapDetailsProps) {
constructor(props: ConfigMapDetailsProps & Dependencies) {
super(props);
makeObservable(this);
}
@ -44,7 +56,7 @@ export class ConfigMapDetails extends React.Component<ConfigMapDetailsProps> {
}
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<ConfigMapDetailsProps> {
...configMap,
data: Object.fromEntries(this.data),
});
Notifications.ok((
this.props.showSuccessNotification((
<p>
{"ConfigMap "}
<b>{configMap.getName()}</b>
@ -60,14 +72,14 @@ export class ConfigMapDetails extends React.Component<ConfigMapDetailsProps> {
</p>
));
} 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<ConfigMapDetailsProps> {
);
}
}
export const ConfigMapDetails = withInjectables<Dependencies, ConfigMapDetailsProps>(NonInjectedConfigMapDetails, {
getProps: (di, props) => ({
...props,
configMapStore: di.inject(configMapStoreInjectable),
showSuccessNotification: di.inject(showSuccessNotificationInjectable),
showErrorNotification: di.inject(showErrorNotificationInjectable),
logger: di.inject(loggerInjectable),
}),
});

View File

@ -20,5 +20,9 @@
&.age {
flex: .5;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={configMap} />,
configMap.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(configMap.getNs()))}
>
{configMap.getNs()}
</a>,
configMap.getKeys().join(", "),
<KubeObjectAge key="age" object={configMap} />,
]}
@ -60,3 +76,11 @@ export class ConfigMaps extends React.Component {
);
}
}
export const ConfigMaps = withInjectables<Dependencies>(NonInjectedConfigMaps, {
getProps: (di, props) => ({
...props,
configMapStore: di.inject(configMapStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -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);

View File

@ -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);

View File

@ -20,5 +20,9 @@
&.age {
flex: .5;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<PodDisruptionBudget> {
}
interface Dependencies {
filterByNamespace: FilterByNamespace;
podDisruptionBudgetStore: PodDisruptionBudgetStore;
}
@observer
export class PodDisruptionBudgets extends React.Component<PodDisruptionBudgetsProps> {
class NonInjectedPodDisruptionBudgets extends React.Component<PodDisruptionBudgetsProps & Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -37,7 +47,7 @@ export class PodDisruptionBudgets extends React.Component<PodDisruptionBudgetsPr
isConfigurable
tableId="configuration_distribution_budgets"
className="PodDisruptionBudgets"
store={podDisruptionBudgetStore}
store={this.props.podDisruptionBudgetStore}
sortingCallbacks={{
[columnId.name]: pdb => pdb.getName(),
[columnId.namespace]: pdb => pdb.getNs(),
@ -64,7 +74,13 @@ export class PodDisruptionBudgets extends React.Component<PodDisruptionBudgetsPr
renderTableContents={pdb => [
pdb.getName(),
<KubeObjectStatusIcon key="icon" object={pdb} />,
pdb.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(pdb.getNs()))}
>
{pdb.getNs()}
</a>,
pdb.getMinAvailable(),
pdb.getMaxUnavailable(),
pdb.getCurrentHealthy(),
@ -76,3 +92,11 @@ export class PodDisruptionBudgets extends React.Component<PodDisruptionBudgetsPr
);
}
}
export const PodDisruptionBudgets = withInjectables<Dependencies, PodDisruptionBudgetsProps>(NonInjectedPodDisruptionBudgets, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
podDisruptionBudgetStore: di.inject(podDisruptionBudgetStoreInjectable),
}),
});

View File

@ -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);

View File

@ -8,5 +8,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={resourceQuota}/>,
resourceQuota.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(resourceQuota.getNs()))}
>
{resourceQuota.getNs()}
</a>,
<KubeObjectAge key="age" object={resourceQuota} />,
]}
addRemoveButtons={{
@ -62,3 +78,11 @@ export class ResourceQuotas extends React.Component {
);
}
}
export const ResourceQuotas = withInjectables<Dependencies>(NonInjectedResourceQuotas, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
resourceQuotaStore: di.inject(resourceQuotaStoreInjectable),
}),
});

View File

@ -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",

View File

@ -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);

View File

@ -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<Secret> {
}
interface Dependencies {
secretStore: SecretStore;
logger: Logger;
showSuccessNotification: ShowNotification;
showCheckedErrorNotification: ShowCheckedErrorNotification;
}
@observer
export class SecretDetails extends React.Component<SecretDetailsProps> {
class NonInjectedSecretDetails extends React.Component<SecretDetailsProps & Dependencies> {
@observable isSaving = false;
@observable data: Partial<Record<string, string>> = {};
@observable revealSecret = observable.set<string>();
constructor(props: SecretDetailsProps) {
constructor(props: SecretDetailsProps & Dependencies) {
super(props);
makeObservable(this);
}
@ -53,10 +66,10 @@ export class SecretDetails extends React.Component<SecretDetailsProps> {
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<SecretDetailsProps> {
}
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<SecretDetailsProps> {
);
}
}
export const SecretDetails = withInjectables<Dependencies, SecretDetailsProps>(NonInjectedSecretDetails, {
getProps: (di, props) => ({
...props,
logger: di.inject(loggerInjectable),
secretStore: di.inject(secretStoreInjectable),
showCheckedErrorNotification: di.inject(showCheckedErrorNotificationInjectable),
showSuccessNotification: di.inject(showSuccessNotificationInjectable),
}),
});

View File

@ -16,5 +16,9 @@
&.labels {
@include table-cell-labels-offsets;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={secret} />,
secret.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(secret.getNs()))}
>
{secret.getNs()}
</a>,
secret.getLabels().map(label => (
<Badge
scrollable
@ -82,3 +98,11 @@ export class Secrets extends React.Component {
);
}
}
export const Secrets = withInjectables<Dependencies>(NonInjectedSecrets, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
secretStore: di.inject(secretStoreInjectable),
}),
});

View File

@ -4,5 +4,7 @@
*/
.CrdResources {
a.filterNamespace {
border-bottom: unset;
}
}

View File

@ -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<string>;
apiManager: ApiManager;
customResourceDefinitionStore: CustomResourceDefinitionStore;
filterByNamespace: FilterByNamespace;
}
@observer
@ -102,7 +106,15 @@ class NonInjectedCustomResources extends React.Component<Dependencies> {
]}
renderTableContents={customResource => [
customResource.getName(),
isNamespaced && customResource.getNs(),
isNamespaced && (
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(customResource.getNs() as string))}
>
{customResource.getNs()}
</a>
),
...extraColumns.map((column) => safeJSONPathValue(customResource, column.jsonPath)),
<KubeObjectAge key="age" object={customResource} />,
]}
@ -129,6 +141,7 @@ export const CustomResources = withInjectables<Dependencies>(NonInjectedCustomRe
...di.inject(customResourcesRouteParametersInjectable),
apiManager: di.inject(apiManagerInjectable),
customResourceDefinitionStore: di.inject(customResourceDefinitionStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -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<Dependencies & EventsProps> {
</>
),
},
event.getNs(),
compact
? (
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(event.getNs()))}
>
{event.getNs()}
</a>
)
: event.getNs(),
<Link
key="link"
to={getDetailsUrl(apiManager.lookupApiLink(involvedObject, event))}
to={this.props.getDetailsUrl(apiManager.lookupApiLink(involvedObject, event))}
onClick={stopPropagation}
>
{`${involvedObject.kind}: ${involvedObject.name}`}
@ -231,5 +246,7 @@ export const Events = withInjectables<Dependencies, EventsProps>(NonInjectedEven
navigateToEvents: di.inject(navigateToEventsInjectable),
apiManager: di.inject(apiManagerInjectable),
eventStore: di.inject(eventStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
getDetailsUrl: di.inject(getDetailsUrlInjectable),
}),
});

View File

@ -20,5 +20,9 @@
}
}
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<RemovableHelmRelease[]>;
releasesArePending: IComputedValue<boolean>;
selectNamespace: (namespace: string) => void;
namespace: IComputedValue<string>;
navigateToHelmReleases: NavigateToHelmReleases;
filterByNamespace: FilterByNamespace;
}
class NonInjectedHelmReleases extends Component<Dependencies> {
@ -50,7 +52,7 @@ class NonInjectedHelmReleases extends Component<Dependencies> {
const namespace = this.props.namespace.get();
if (namespace) {
this.props.selectNamespace(namespace);
this.props.filterByNamespace(namespace);
}
}
@ -186,7 +188,13 @@ class NonInjectedHelmReleases extends Component<Dependencies> {
]}
renderTableContents={release => [
release.getName(),
release.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(release.getNs()))}
>
{release.getNs()}
</a>,
release.getChart(),
release.getRevision(),
release.getVersion(),
@ -213,20 +221,12 @@ class NonInjectedHelmReleases extends Component<Dependencies> {
}
}
export const HelmReleases = withInjectables<Dependencies>(
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<Dependencies>(NonInjectedHelmReleases, {
getProps: (di) => ({
releases: di.inject(removableReleasesInjectable),
releasesArePending: di.inject(releasesInjectable).pending,
navigateToHelmReleases: di.inject(navigateToHelmReleasesInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
...di.inject(helmReleasesRouteParametersInjectable),
}),
});

View File

@ -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;

View File

@ -12,5 +12,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={endpoint} />,
endpoint.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(endpoint.getNs()))}
>
{endpoint.getNs()}
</a>,
endpoint.toString(),
<KubeObjectAge key="age" object={endpoint} />,
]}
@ -65,3 +81,11 @@ export class Endpoints extends React.Component {
);
}
}
export const Endpoints = withInjectables<Dependencies>(NonInjectedEndpoints, {
getProps: (di, props) => ({
...props,
endpointsStore: di.inject(endpointsStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -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);

View File

@ -31,5 +31,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={ingress} />,
ingress.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(ingress.getNs()))}
>
{ingress.getNs()}
</a>,
ingress.getLoadBalancers().map(lb => <p key={lb}>{lb}</p>),
computeRouteDeclarations(ingress).map(decl => (
decl.displayAsLink
@ -90,3 +106,11 @@ export class Ingresses extends React.Component {
);
}
}
export const Ingresses = withInjectables<Dependencies>(NonInjectedIngresses, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
ingressStore: di.inject(ingressStoreInjectable),
}),
});

View File

@ -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);

View File

@ -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);

View File

@ -8,5 +8,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={networkPolicy} />,
networkPolicy.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(networkPolicy.getNs()))}
>
{networkPolicy.getNs()}
</a>,
networkPolicy.getTypes().join(", "),
<KubeObjectAge key="age" object={networkPolicy} />,
]}
@ -58,3 +74,11 @@ export class NetworkPolicies extends React.Component {
);
}
}
export const NetworkPolicies = withInjectables<Dependencies>(NonInjectedNetworkPolicies, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
networkPolicyStore: di.inject(networkPolicyStoreInjectable),
}),
});

View File

@ -13,5 +13,9 @@
@include port-forward-status-colors;
flex: 0.6;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<string>;
navigateToPortForwards: NavigateToPortForwards;
filterByNamespace: FilterByNamespace;
}
@observer
@ -128,7 +132,13 @@ class NonInjectedPortForwards extends React.Component<Dependencies> {
]}
renderTableContents={item => [
item.getName(),
item.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(item.getNs()))}
>
{item.getNs()}
</a>,
item.getKind(),
item.getPort(),
item.getForwardPort(),
@ -158,19 +168,12 @@ class NonInjectedPortForwards extends React.Component<Dependencies> {
}
}
export const PortForwards = withInjectables<Dependencies>(
NonInjectedPortForwards,
{
getProps: (di) => {
const routeParameters = di.inject(portForwardsRouteParametersInjectable);
return {
portForwardStore: di.inject(portForwardStoreInjectable),
forwardport: routeParameters.forwardport,
navigateToPortForwards: di.inject(navigateToPortForwardsInjectable),
};
},
},
);
export const PortForwards = withInjectables<Dependencies>(NonInjectedPortForwards, {
getProps: (di) => ({
portForwardStore: di.inject(portForwardStoreInjectable),
...di.inject(portForwardsRouteParametersInjectable),
navigateToPortForwards: di.inject(navigateToPortForwardsInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -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);

View File

@ -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<ServiceDetailsEndpointProps> {
class NonInjectedServiceDetailsEndpoint extends React.Component<ServiceDetailsEndpointProps & Dependencies> {
render() {
const { endpoints } = this.props;
if (!endpoints && !endpointsStore.isLoaded) return (
<div className="PodDetailsList flex justify-center"><Spinner/></div>
);
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<ServiceDetailsEndpoi
<TableRow
key={endpoints.getId()}
nowrap
onClick={prevDefault(() => showDetails(endpoints.selfLink, false))}
onClick={prevDefault(() => this.props.showDetails(endpoints.selfLink, false))}
>
<TableCell className="name">{endpoints.getName()}</TableCell>
<TableCell className="endpoints">{ endpoints.toString()}</TableCell>
@ -61,3 +63,11 @@ export class ServiceDetailsEndpoint extends React.Component<ServiceDetailsEndpoi
);
}
}
export const ServiceDetailsEndpoint = withInjectables<Dependencies, ServiceDetailsEndpointProps>(NonInjectedServiceDetailsEndpoint, {
getProps: (di, props) => ({
...props,
logger: di.inject(loggerInjectable),
showDetails: di.inject(showDetailsInjectable),
}),
});

View File

@ -25,5 +25,9 @@
@include service-status-colors;
flex: 0.6;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
return (
<SiblingsInTabLayout>
@ -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(),
<KubeObjectStatusIcon key="icon" object={service} />,
service.getNs(),
service.getType(),
service.getClusterIp(),
service.getPorts().join(", "),
externalIps.join(", ") || "-",
service.getSelector().map(label => <Badge key={label} label={label} />),
<KubeObjectAge key="age" object={service} />,
{ title: service.getStatus(), className: service.getStatus().toLowerCase() },
];
}}
renderTableContents={service => [
service.getName(),
<KubeObjectStatusIcon key="icon" object={ service } />,
<a
key="namespace"
className="filterNamespace"
onClick={ prevDefault(() => this.props.filterByNamespace(service.getNs())) }
>
{ service.getNs() }
</a>,
service.getType(),
service.getClusterIp(),
service.getPorts().join(", "),
formatExternalIps(service),
service.getSelector().map(label => <Badge key={ label } label={ label } />),
<KubeObjectAge key="age" object={ service } />,
{ title: service.getStatus(), className: service.getStatus().toLowerCase() },
]}
/>
</SiblingsInTabLayout>
);
}
}
export const Services = withInjectables<Dependencies>(NonInjectedServices, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
serviceStore: di.inject(serviceStoreInjectable),
}),
});

View File

@ -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);

View File

@ -38,5 +38,9 @@
&.age {
flex: 0.4;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
const {
persistentVolumeClaimStore,
filterByNamespace,
getDetailsUrl,
podStore,
storageClassApi,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -67,14 +90,20 @@ export class PersistentVolumeClaims extends React.Component {
renderTableContents={pvc => {
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(),
<KubeObjectStatusIcon key="icon" object={pvc} />,
pvc.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(pvc.getNs()))}
>
{pvc.getNs()}
</a>,
<Link
key="link"
to={storageClassDetailsUrl}
@ -101,3 +130,14 @@ export class PersistentVolumeClaims extends React.Component {
);
}
}
export const PersistentVolumeClaims = withInjectables<Dependencies>(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),
}),
});

View File

@ -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,
});

View File

@ -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<ClusterRole, ClusterRoleApi, ClusterRoleData> {
export class ClusterRoleStore extends KubeObjectStore<ClusterRole, ClusterRoleApi, ClusterRoleData> {
protected sortItems(items: ClusterRole[]) {
return super.sortItems(items, [
clusterRole => clusterRole.kind,

View File

@ -12,5 +12,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
const {
clusterRoleStore,
roleBindingStore,
roleStore,
serviceAccountStore,
filterByNamespace,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -55,7 +79,13 @@ export class RoleBindings extends React.Component {
renderTableContents={binding => [
binding.getName(),
<KubeObjectStatusIcon key="icon" object={binding} />,
binding.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(binding.getNs()))}
>
{binding.getNs()}
</a>,
binding.getSubjectNames(),
<KubeObjectAge key="age" object={binding} />,
]}
@ -69,3 +99,14 @@ export class RoleBindings extends React.Component {
);
}
}
export const RoleBindings = withInjectables<Dependencies>(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),
}),
});

View File

@ -12,5 +12,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
const {
filterByNamespace,
roleStore,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -48,7 +63,13 @@ export class Roles extends React.Component {
renderTableContents={role => [
role.getName(),
<KubeObjectStatusIcon key="icon" object={role} />,
role.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(role.getNs()))}
>
{role.getNs()}
</a>,
<KubeObjectAge key="age" object={role} />,
]}
addRemoveButtons={{
@ -61,3 +82,11 @@ export class Roles extends React.Component {
);
}
}
export const Roles = withInjectables<Dependencies>(NonInjectedRoles, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
roleStore: di.inject(roleStoreInjectable),
}),
});

View File

@ -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<ServiceAccount> {
}
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<ServiceAccountsDetailsProps> {
class NonInjectedServiceAccountsDetails extends React.Component<ServiceAccountsDetailsProps & Dependencies> {
readonly secrets = observable.array<Secret | string>();
readonly imagePullSecrets = observable.array<Secret | string>();
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<ServiceAccountsDetai
return;
}
const defensiveLoadSecret = defensiveLoadSecretIn(namespace);
const defensiveLoadSecret = this.defensiveLoadSecretIn(namespace);
const secretLoaders = Promise.all(serviceAccount.getSecrets().map(defensiveLoadSecret));
const imagePullSecretLoaders = Promise.all(serviceAccount.getImagePullSecrets().map(defensiveLoadSecret));
@ -108,7 +116,7 @@ export class ServiceAccountsDetails extends React.Component<ServiceAccountsDetai
}
return (
<Link key={secret.getId()} to={getDetailsUrl(secret.selfLink)}>
<Link key={secret.getId()} to={this.props.getDetailsUrl(secret.selfLink)}>
{secret.getName()}
</Link>
);
@ -116,7 +124,7 @@ export class ServiceAccountsDetails extends React.Component<ServiceAccountsDetai
}
render() {
const { object: serviceAccount } = this.props;
const { object: serviceAccount, secretStore } = this.props;
if (!serviceAccount) {
return null;
@ -150,3 +158,11 @@ export class ServiceAccountsDetails extends React.Component<ServiceAccountsDetai
);
}
}
export const ServiceAccountsDetails = withInjectables<Dependencies, ServiceAccountsDetailsProps>(NonInjectedServiceAccountsDetails, {
getProps: (di, props) => ({
...props,
getDetailsUrl: di.inject(getDetailsUrlInjectable),
secretStore: di.inject(secretStoreInjectable),
}),
});

View File

@ -8,5 +8,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
const {
filterByNamespace,
serviceAccountStore,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -48,7 +63,13 @@ export class ServiceAccounts extends React.Component {
renderTableContents={account => [
account.getName(),
<KubeObjectStatusIcon key="icon" object={account} />,
account.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(account.getNs()))}
>
{account.getNs()}
</a>,
<KubeObjectAge key="age" object={account} />,
]}
addRemoveButtons={{
@ -62,3 +83,10 @@ export class ServiceAccounts extends React.Component {
}
}
export const ServiceAccounts = withInjectables<Dependencies>(NonInjectedServiceAccounts, {
getProps: (di, props) => ({
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
serviceAccountStore: di.inject(serviceAccountStoreInjectable),
}),
});

View File

@ -8,5 +8,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies>{
cronJobStore,
eventStore,
jobStore,
filterByNamespace,
} = this.props;
return (
@ -83,7 +88,13 @@ class NonInjectedCronJobs extends React.Component<Dependencies>{
renderTableContents={cronJob => [
cronJob.getName(),
<KubeObjectStatusIcon key="icon" object={cronJob} />,
cronJob.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(cronJob.getNs()))}
>
{cronJob.getNs()}
</a>,
cronJob.isNeverRun() ? "never" : cronJob.getSchedule(),
cronJob.getSuspendFlag(),
cronJobStore.getActiveJobsNum(cronJob),
@ -98,9 +109,10 @@ class NonInjectedCronJobs extends React.Component<Dependencies>{
export const CronJobs = withInjectables<Dependencies>(NonInjectedCronJobs, {
getProps: (di, props) => ({
...props,
cronJobStore: di.inject(cronJobStoreInjectable),
eventStore: di.inject(eventStoreInjectable),
jobStore: di.inject(jobStoreInjectable),
...props,
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -21,5 +21,9 @@
flex-grow: 1.5;
@include table-cell-labels-offsets;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
getPodsLength(daemonSet: DaemonSet) {
return daemonSetStore.getChildPods(daemonSet).length;
return this.props.daemonSetStore.getChildPods(daemonSet).length;
}
render() {
const {
daemonSetStore,
eventStore,
filterByNamespace,
podStore,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -61,7 +82,13 @@ export class DaemonSets extends React.Component {
]}
renderTableContents={daemonSet => [
daemonSet.getName(),
daemonSet.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(daemonSet.getNs()))}
>
{daemonSet.getNs()}
</a>,
this.getPodsLength(daemonSet),
<KubeObjectStatusIcon key="icon" object={daemonSet} />,
daemonSet.getNodeSelectors().map(selector => (
@ -78,3 +105,13 @@ export class DaemonSets extends React.Component {
);
}
}
export const DaemonSets = withInjectables<Dependencies>(NonInjectedDaemonSets, {
getProps: (di, props) => ({
...props,
daemonSetStore: di.inject(daemonSetStoreInjectable),
eventStore: di.inject(eventStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
podStore: di.inject(podStoreInjectable),
}),
});

View File

@ -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);

View File

@ -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<DeploymentReplicaSetsProps> {
class NonInjectedDeploymentReplicaSets extends React.Component<DeploymentReplicaSetsProps & Dependencies> {
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 (
<div className="ReplicaSets"><Spinner center/></div>
@ -95,6 +107,14 @@ export class DeploymentReplicaSets extends React.Component<DeploymentReplicaSets
}
}
export const DeploymentReplicaSets = withInjectables<Dependencies, DeploymentReplicaSetsProps>(NonInjectedDeploymentReplicaSets, {
getProps: (di, props) => ({
...props,
replicaSetStore: di.inject(replicaSetStoreInjectable),
showDetails: di.inject(showDetailsInjectable),
}),
});
export function ReplicaSetMenu(props: KubeObjectMenuProps<ReplicaSet>) {
return (
<KubeObjectMenu {...props}/>

View File

@ -42,5 +42,9 @@
}
}
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
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 (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -82,7 +99,13 @@ export class Deployments extends React.Component {
renderTableContents={deployment => [
deployment.getName(),
<KubeObjectStatusIcon key="icon" object={deployment} />,
deployment.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(deployment.getNs()))}
>
{deployment.getNs()}
</a>,
this.renderPods(deployment),
deployment.getReplicas(),
<KubeObjectAge key="age" object={deployment} />,
@ -93,3 +116,12 @@ export class Deployments extends React.Component {
);
}
}
export const Deployments = withInjectables<Dependencies>(NonInjectedDeployments, {
getProps: (di, props) => ({
...props,
deploymentStore: di.inject(deploymentStoreInjectable),
eventStore: di.inject(eventStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -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);

View File

@ -18,5 +18,9 @@
&.conditions {
@include job-condition-colors;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
const {
eventStore,
filterByNamespace,
jobStore,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -57,7 +75,13 @@ export class Jobs extends React.Component {
return [
job.getName(),
job.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(job.getNs()))}
>
{job.getNs()}
</a>,
`${job.getCompletions()} / ${job.getDesiredCompletions()}`,
<KubeObjectStatusIcon key="icon" object={job} />,
<KubeObjectAge key="age" object={job} />,
@ -72,3 +96,12 @@ export class Jobs extends React.Component {
);
}
}
export const Jobs = withInjectables<Dependencies>(NonInjectedJobs, {
getProps: (di, props) => ({
...props,
eventStore: di.inject(eventStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
jobStore: di.inject(jobStoreInjectable),
}),
});

View File

@ -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);

View File

@ -37,5 +37,9 @@
@include pod-status-colors;
flex-grow: 0.7;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
expandable={false}
/>,
<KubeObjectStatusIcon key="icon" object={pod} />,
pod.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => this.props.filterByNamespace(pod.getNs()))}
>
{pod.getNs()}
</a>,
this.renderContainersStatus(pod),
pod.getRestartsCount(),
pod.getOwnerRefs().map(ref => {
@ -201,5 +210,6 @@ export const Pods = withInjectables<Dependencies>(NonInjectedPods, {
nodeApi: di.inject(nodeApiInjectable),
eventStore: di.inject(eventStoreInjectable),
podStore: di.inject(podStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
}),
});

View File

@ -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);

View File

@ -12,5 +12,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
render() {
const {
eventStore,
filterByNamespace,
replicaSetStore,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -58,7 +76,13 @@ export class ReplicaSets extends React.Component {
renderTableContents={replicaSet => [
replicaSet.getName(),
<KubeObjectStatusIcon key="icon" object={replicaSet} />,
replicaSet.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(replicaSet.getNs()))}
>
{replicaSet.getNs()}
</a>,
replicaSet.getDesired(),
replicaSet.getCurrent(),
replicaSet.getReady(),
@ -70,3 +94,11 @@ export class ReplicaSets extends React.Component {
}
}
export const ReplicaSets = withInjectables<Dependencies>(NonInjectedReplicaSets, {
getProps: (di, props) => ({
...props,
eventStore: di.inject(eventStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
replicaSetStore: di.inject(replicaSetStoreInjectable),
}),
});

View File

@ -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);

View File

@ -16,5 +16,9 @@
&.warning {
@include table-cell-warning;
}
a.filterNamespace {
border-bottom: unset;
}
}
}

View File

@ -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<Dependencies> {
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 (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -61,7 +82,13 @@ export class StatefulSets extends React.Component {
]}
renderTableContents={statefulSet => [
statefulSet.getName(),
statefulSet.getNs(),
<a
key="namespace"
className="filterNamespace"
onClick={prevDefault(() => filterByNamespace(statefulSet.getNs()))}
>
{statefulSet.getNs()}
</a>,
this.renderPods(statefulSet),
statefulSet.getReplicas(),
<KubeObjectStatusIcon key="icon" object={statefulSet} />,
@ -72,3 +99,13 @@ export class StatefulSets extends React.Component {
);
}
}
export const StatefulSets = withInjectables<Dependencies>(NonInjectedStatefulSets, {
getProps: (di, props) => ({
...props,
eventStore: di.inject(eventStoreInjectable),
filterByNamespace: di.inject(filterByNamespaceInjectable),
podStore: di.inject(podStoreInjectable),
statefulSetStore: di.inject(statefulSetStoreInjectable),
}),
});

View File

@ -499,6 +499,7 @@ export const getApplicationBuilder = () => {
api: windowDi.inject(namespaceApiInjectable),
items: namespaceItems,
selectNamespaces: () => {},
selectSingle: () => {},
getByPath: () => undefined,
pickOnlySelected: () => [],
isSelectedAll: () => false,