From 54e874f646896c9f22a278cf8d0f58d267fdbbb2 Mon Sep 17 00:00:00 2001
From: Roman
Date: Thu, 16 Feb 2023 14:48:24 +0200
Subject: [PATCH 1/8] Replication Controllers (new resource view) (#7154)
* New resource view: ReplicationController -- scaffolding files
Signed-off-by: Roman
* fix: inappropriate names after copy-pasting
Signed-off-by: Roman
* update replication controller api types/spec, fix menu title
Signed-off-by: Roman
* items list + details list views (added contents from replication controllers), lint fixes
Signed-off-by: Roman
* allow to scale replication controllers
Signed-off-by: Roman
* switched for scaling replicas with `Slider` component instead of `Buttons+Input`
Signed-off-by: Roman
---------
Signed-off-by: Roman
---
...e-to-replication-controllers.injectable.ts | 20 +++
...replicationcontrollers-route.injectable.ts | 24 +++
.../src/common/k8s-api/endpoints/index.ts | 1 +
.../replication-controller.api.injectable.ts | 23 +++
.../endpoints/replication-controller.api.ts | 149 ++++++++++++++++++
packages/core/src/common/rbac.ts | 7 +-
.../index.ts | 7 +
...-controllers-route-component.injectable.ts | 24 +++
.../replicationcontroller-details.module.scss | 16 ++
.../replicationcontroller-details.tsx | 122 ++++++++++++++
...ioncontroller-sidebar-items.injectable.tsx | 39 +++++
.../replicationcontroller-store.injectable.ts | 26 +++
.../replicationcontroller-store.ts | 23 +++
.../replicationcontrollers.module.scss | 8 +
.../replicationcontrollers.tsx | 86 ++++++++++
...ation-controller-detail-item.injectable.ts | 35 ++++
packages/core/src/renderer/utils/rbac.ts | 1 +
17 files changed, 610 insertions(+), 1 deletion(-)
create mode 100644 packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/navigate-to-replication-controllers.injectable.ts
create mode 100644 packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable.ts
create mode 100644 packages/core/src/common/k8s-api/endpoints/replication-controller.api.injectable.ts
create mode 100644 packages/core/src/common/k8s-api/endpoints/replication-controller.api.ts
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/index.ts
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replication-controllers-route-component.injectable.ts
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.module.scss
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.tsx
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-sidebar-items.injectable.tsx
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.injectable.ts
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.ts
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.module.scss
create mode 100644 packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.tsx
create mode 100644 packages/core/src/renderer/components/kube-object-details/kube-object-detail-items/implementations/replication-controller-detail-item.injectable.ts
diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/navigate-to-replication-controllers.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/navigate-to-replication-controllers.injectable.ts
new file mode 100644
index 0000000000..240ad0f37e
--- /dev/null
+++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/navigate-to-replication-controllers.injectable.ts
@@ -0,0 +1,20 @@
+/**
+ * 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 replicationControllersRouteInjectable from "./replicationcontrollers-route.injectable";
+import { navigateToRouteInjectionToken } from "../../../../navigate-to-route-injection-token";
+
+const navigateToReplicationControllersInjectable = getInjectable({
+ id: "navigate-to-replicationcontrollers",
+
+ instantiate: (di) => {
+ const navigateToRoute = di.inject(navigateToRouteInjectionToken);
+ const route = di.inject(replicationControllersRouteInjectable);
+
+ return () => navigateToRoute(route);
+ },
+});
+
+export default navigateToReplicationControllersInjectable;
diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable.ts
new file mode 100644
index 0000000000..77d87abc96
--- /dev/null
+++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable.ts
@@ -0,0 +1,24 @@
+/**
+ * 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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
+import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
+
+const replicationControllersRouteInjectable = getInjectable({
+ id: "replicationcontrollers-route",
+
+ instantiate: (di) => ({
+ path: "/replicationcontrollers",
+ clusterFrame: true,
+ isEnabled: di.inject(shouldShowResourceInjectionToken, {
+ apiName: "replicationcontrollers",
+ group: "", // core
+ }),
+ }),
+
+ injectionToken: frontEndRouteInjectionToken,
+});
+
+export default replicationControllersRouteInjectable;
diff --git a/packages/core/src/common/k8s-api/endpoints/index.ts b/packages/core/src/common/k8s-api/endpoints/index.ts
index 0314c6b282..8fb6cbdabd 100644
--- a/packages/core/src/common/k8s-api/endpoints/index.ts
+++ b/packages/core/src/common/k8s-api/endpoints/index.ts
@@ -33,6 +33,7 @@ export * from "./pod-metrics.api";
export * from "./pod-security-policy.api";
export * from "./priority-class.api";
export * from "./replica-set.api";
+export * from "./replication-controller.api";
export * from "./resource-quota.api";
export * from "./role.api";
export * from "./role-binding.api";
diff --git a/packages/core/src/common/k8s-api/endpoints/replication-controller.api.injectable.ts b/packages/core/src/common/k8s-api/endpoints/replication-controller.api.injectable.ts
new file mode 100644
index 0000000000..6d65f446b5
--- /dev/null
+++ b/packages/core/src/common/k8s-api/endpoints/replication-controller.api.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
+import loggerInjectable from "../../logger.injectable";
+import maybeKubeApiInjectable from "../maybe-kube-api.injectable";
+import { ReplicationControllerApi } from "./replication-controller.api";
+
+const replicationControllerApiInjectable = getInjectable({
+ id: "replication-controller-api",
+ instantiate: (di) => {
+ return new ReplicationControllerApi({
+ logger: di.inject(loggerInjectable),
+ maybeKubeApi: di.inject(maybeKubeApiInjectable),
+ });
+ },
+
+ injectionToken: kubeApiInjectionToken,
+});
+
+export default replicationControllerApiInjectable;
diff --git a/packages/core/src/common/k8s-api/endpoints/replication-controller.api.ts b/packages/core/src/common/k8s-api/endpoints/replication-controller.api.ts
new file mode 100644
index 0000000000..b87b7a81a8
--- /dev/null
+++ b/packages/core/src/common/k8s-api/endpoints/replication-controller.api.ts
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
+import { KubeApi } from "../kube-api";
+import type {
+ BaseKubeObjectCondition, KubeObjectMetadata,
+ KubeObjectStatus,
+ NamespaceScopedMetadata,
+} from "../kube-object";
+import { KubeObject } from "../kube-object";
+import type { PodTemplateSpec } from "./types";
+
+export class ReplicationControllerApi extends KubeApi {
+ constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
+ super(deps, {
+ ...opts ?? {},
+ objectConstructor: ReplicationController,
+ });
+ }
+
+ protected getScaleApiUrl(params: { namespace: string; name: string }) {
+ return `${this.formatUrlForNotListing(params)}/scale`;
+ }
+
+ getScale(params: { namespace: string; name: string }): Promise {
+ return this.request.get(this.getScaleApiUrl(params));
+ }
+
+ scale(params: { namespace: string; name: string }, replicas: number): Promise {
+ return this.request.patch(this.getScaleApiUrl(params), {
+ data: {
+ metadata: params,
+ spec: {
+ replicas,
+ },
+ },
+ }, {
+ headers: {
+ "content-type": "application/strategic-merge-patch+json",
+ },
+ });
+ }
+}
+
+export interface Scale {
+ apiVersion: "autoscaling/v1";
+ kind: "Scale";
+ metadata: KubeObjectMetadata;
+ spec: {
+ replicas: number;
+ };
+ status: {
+ replicas: number;
+ selector: string;
+ };
+}
+
+export interface ReplicationControllerSpec {
+ /**
+ * Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available.
+ * Defaults to 0 (pod will be considered available as soon as it is ready)
+ */
+ minReadySeconds?: number;
+ /**
+ * Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified.
+ * Defaults to 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller
+ */
+ replicas?: number;
+ /**
+ * Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template.
+ * Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template.
+ * More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
+ */
+ selector?: Record;
+ /**
+ * Template is the object that describes the pod that will be created if insufficient replicas are detected. This takes precedence over a TemplateRef.
+ * More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template
+ */
+ template: PodTemplateSpec;
+}
+
+export interface ReplicationControllerStatus extends KubeObjectStatus {
+ /**
+ * The number of available replicas (ready for at least minReadySeconds) for this replication controller.
+ */
+ availableReplicas: number;
+ /**
+ * The number of pods that have labels matching the labels of the pod template of the replication controller.
+ */
+ fullyLabeledReplicas: number;
+ /**
+ * ObservedGeneration reflects the generation of the most recently observed replication controller.
+ */
+ observedGeneration: number;
+ /**
+ * The number of ready replicas for this replication controller.
+ */
+ readyReplicas: number;
+ /**
+ * Replicas is the most recently observed number of replicas.
+ * More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller
+ */
+ replicas: number;
+}
+
+export class ReplicationController extends KubeObject<
+ NamespaceScopedMetadata,
+ ReplicationControllerStatus,
+ ReplicationControllerSpec
+> {
+ static kind = "ReplicationController";
+ static namespaced = true;
+ static apiBase = "/api/v1/replicationcontrollers";
+
+ getMinReadySeconds(): number {
+ return this.spec?.minReadySeconds ?? 0;
+ }
+
+ getGeneration() {
+ return this.status?.observedGeneration;
+ }
+
+ getSelectorLabels(): string[] {
+ return KubeObject.stringifyLabels(this.spec.selector);
+ }
+
+ getReplicas(): number | undefined {
+ return this.status?.replicas;
+ }
+
+ getDesiredReplicas(): number {
+ return this.spec?.replicas ?? 0;
+ }
+
+ getAvailableReplicas(): number | undefined {
+ return this.status?.availableReplicas;
+ }
+
+ getLabeledReplicas(): number | undefined {
+ return this.status?.fullyLabeledReplicas;
+ }
+
+ getConditions(): BaseKubeObjectCondition[] {
+ return this.status?.conditions ?? [];
+ }
+}
diff --git a/packages/core/src/common/rbac.ts b/packages/core/src/common/rbac.ts
index e2ccad3806..03b4fd1de9 100644
--- a/packages/core/src/common/rbac.ts
+++ b/packages/core/src/common/rbac.ts
@@ -6,7 +6,7 @@
export type KubeResource =
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" |
"secrets" | "configmaps" | "ingresses" | "ingressclasses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
- "pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" |
+ "pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "replicationcontrollers" | "jobs" | "cronjobs" |
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "verticalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" |
"priorityclasses" | "runtimeclasses" |
"roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts";
@@ -171,6 +171,11 @@ export const apiResourceRecord: Record = {
group: "apps",
namespaced: true,
},
+ replicationcontrollers: {
+ kind: "ReplicationController",
+ group: "", // core
+ namespaced: true,
+ },
roles: {
kind: "Role",
group: "rbac.authorization.k8s.io",
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/index.ts b/packages/core/src/renderer/components/+workloads-replicationcontrollers/index.ts
new file mode 100644
index 0000000000..5f9390ae2f
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/index.ts
@@ -0,0 +1,7 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+export * from "./replicationcontrollers";
+export * from "./replicationcontroller-details";
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replication-controllers-route-component.injectable.ts b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replication-controllers-route-component.injectable.ts
new file mode 100644
index 0000000000..9049b69076
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replication-controllers-route-component.injectable.ts
@@ -0,0 +1,24 @@
+/**
+ * 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 { ReplicationControllers } from "./replicationcontrollers";
+import {
+ routeSpecificComponentInjectionToken,
+} from "../../routes/route-specific-component-injection-token";
+import replicationControllersRouteInjectable
+ from "../../../common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable";
+
+const replicationControllersRouteComponentInjectable = getInjectable({
+ id: "replicationcontroller-route-component",
+
+ instantiate: (di) => ({
+ route: di.inject(replicationControllersRouteInjectable),
+ Component: ReplicationControllers,
+ }),
+
+ injectionToken: routeSpecificComponentInjectionToken,
+});
+
+export default replicationControllersRouteComponentInjectable;
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.module.scss b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.module.scss
new file mode 100644
index 0000000000..eb1d11143a
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.module.scss
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+.ReplicationControllerDetails {
+ .replicas {
+ display: flex;
+ gap: calc(var(--margin) * 2);
+ align-items: center;
+
+ > * {
+ flex-shrink: 0;
+ }
+ }
+}
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.tsx b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.tsx
new file mode 100644
index 0000000000..44032e53ff
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-details.tsx
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import styles from "./replicationcontroller-details.module.scss";
+import React from "react";
+import { action, makeObservable, observable } from "mobx";
+import { observer } from "mobx-react";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import { DrawerItem, DrawerTitle } from "../drawer";
+import { Badge } from "../badge";
+import type { KubeObjectDetailsProps } from "../kube-object-details";
+import type {
+ ReplicationController,
+ ReplicationControllerApi,
+} from "../../../common/k8s-api/endpoints";
+import replicationControllerApiInjectable
+ from "../../../common/k8s-api/endpoints/replication-controller.api.injectable";
+import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable";
+import type { ShowNotification } from "../notifications";
+import { Slider } from "../slider";
+
+export interface ReplicationControllerDetailsProps extends KubeObjectDetailsProps {
+}
+
+interface Dependencies {
+ api: ReplicationControllerApi;
+ showNotificationError: ShowNotification;
+}
+
+@observer
+class NonInjectedReplicationControllerDetails extends React.Component {
+ @observable sliderReplicasValue = this.props.object.getDesiredReplicas();
+ @observable sliderReplicasDisabled = false;
+
+ constructor(props: Props) {
+ super(props);
+ makeObservable(this);
+ }
+
+ @action
+ async scale(replicas: number) {
+ const { object: resource, api, showNotificationError } = this.props;
+
+ try {
+ await api.scale({
+ name: resource.getName(),
+ namespace: resource.getNs(),
+ }, replicas);
+ } catch (error) {
+ this.sliderReplicasValue = resource.getDesiredReplicas(); // rollback to last valid value
+ showNotificationError(error as Error);
+ }
+ }
+
+ @action
+ async onScaleSliderChangeCommitted(evt: React.FormEvent, replicas: number) {
+ this.sliderReplicasDisabled = true;
+ await this.scale(replicas);
+ this.sliderReplicasDisabled = false;
+ }
+
+ render() {
+ const { object: resource } = this.props;
+
+ return (
+
+
+ Spec
+
+
+
+
{resource.getDesiredReplicas()}
+
Scale
+
this.sliderReplicasValue = value}
+ onChangeCommitted={(event, value) => this.onScaleSliderChangeCommitted(event, value as number)}
+ />
+
+
+
+ {
+ resource.getSelectorLabels().map(label => ())
+ }
+
+
+
+ Status
+
+
+ {resource.getReplicas()}
+
+
+ {resource.getAvailableReplicas()}
+
+
+ {resource.getLabeledReplicas()}
+
+
+ {resource.getGeneration()}
+
+
+ {`${resource.getMinReadySeconds()} seconds`}
+
+
+ );
+ }
+}
+
+export const ReplicationControllerDetails = withInjectables(NonInjectedReplicationControllerDetails, {
+ getProps: (di, props) => ({
+ ...props,
+ api: di.inject(replicationControllerApiInjectable),
+ showNotificationError: di.inject(showErrorNotificationInjectable),
+ }),
+});
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-sidebar-items.injectable.tsx b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-sidebar-items.injectable.tsx
new file mode 100644
index 0000000000..670db2fd16
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-sidebar-items.injectable.tsx
@@ -0,0 +1,39 @@
+/**
+ * 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 { computed } from "mobx";
+import { workloadsSidebarItemId } from "../+workloads/workloads-sidebar-items.injectable";
+import { sidebarItemsInjectionToken } from "../layout/sidebar-items.injectable";
+import routeIsActiveInjectable from "../../routes/route-is-active.injectable";
+import replicationControllersRouteInjectable
+ from "../../../common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable";
+import navigateToReplicationControllersInjectable
+ from "../../../common/front-end-routing/routes/cluster/workloads/replicationcontrollers/navigate-to-replication-controllers.injectable";
+
+const replicationControllerSidebarItemsInjectable = getInjectable({
+ id: "replicationctrl-sidebar-items",
+
+ instantiate: (di) => {
+ const route = di.inject(replicationControllersRouteInjectable);
+ const navigateToPage = di.inject(navigateToReplicationControllersInjectable);
+ const routeIsActive = di.inject(routeIsActiveInjectable, route);
+
+ return computed(() => [
+ {
+ id: "replication-controllers",
+ parentId: workloadsSidebarItemId,
+ title: "Replication Controllers",
+ onClick: navigateToPage,
+ isActive: routeIsActive,
+ isVisible: route.isEnabled,
+ orderNumber: 61,
+ },
+ ]);
+ },
+
+ injectionToken: sidebarItemsInjectionToken,
+});
+
+export default replicationControllerSidebarItemsInjectable;
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.injectable.ts b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.injectable.ts
new file mode 100644
index 0000000000..5749acf915
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.injectable.ts
@@ -0,0 +1,26 @@
+/**
+ * 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 { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/kube-object-store-token";
+import { ReplicationControllerStore } from "./replicationcontroller-store";
+import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
+import loggerInjectable from "../../../common/logger.injectable";
+import replicationControllerApiInjectable
+ from "../../../common/k8s-api/endpoints/replication-controller.api.injectable";
+
+const replicationControllerStoreInjectable = getInjectable({
+ id: "replication-controller-store",
+ instantiate: (di) => {
+ const api = di.inject(replicationControllerApiInjectable);
+
+ return new ReplicationControllerStore({
+ context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
+ logger: di.inject(loggerInjectable),
+ }, api);
+ },
+ injectionToken: kubeObjectStoreInjectionToken,
+});
+
+export default replicationControllerStoreInjectable;
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.ts b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.ts
new file mode 100644
index 0000000000..9b5243c219
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontroller-store.ts
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import type {
+ ReplicationController,
+ ReplicationControllerApi,
+} from "../../../common/k8s-api/endpoints";
+import type {
+ KubeObjectStoreDependencies,
+ KubeObjectStoreOptions,
+} from "../../../common/k8s-api/kube-object.store";
+import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
+
+export interface ReplicationControllerStoreDependencies extends KubeObjectStoreDependencies {
+}
+
+export class ReplicationControllerStore extends KubeObjectStore {
+ constructor(protected readonly dependencies: ReplicationControllerStoreDependencies, api: ReplicationControllerApi, opts?: KubeObjectStoreOptions) {
+ super(dependencies, api, opts);
+ }
+}
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.module.scss b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.module.scss
new file mode 100644
index 0000000000..db65602d19
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.module.scss
@@ -0,0 +1,8 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+.ReplicationControllers {
+
+}
diff --git a/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.tsx b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.tsx
new file mode 100644
index 0000000000..00f13feecc
--- /dev/null
+++ b/packages/core/src/renderer/components/+workloads-replicationcontrollers/replicationcontrollers.tsx
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import styles from "./replicationcontrollers.module.scss";
+import React from "react";
+import { observer } from "mobx-react";
+import { KubeObjectListLayout } from "../kube-object-list-layout";
+import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
+import type { ReplicationControllerStore } from "./replicationcontroller-store";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import replicationControllerStoreInjectable from "./replicationcontroller-store.injectable";
+import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
+import { Badge } from "../badge";
+
+enum columnId {
+ name = "name",
+ namespace = "namespace",
+ replicas = "replicas",
+ replicasDesired = "replicasDesired",
+ selector = "selector",
+}
+
+interface Dependencies {
+ store: ReplicationControllerStore;
+}
+
+const NonInjectedReplicationControllers = observer((props: Dependencies) => {
+ return (
+
+ item.getName(),
+ [columnId.namespace]: item => item.getNs(),
+ [columnId.selector]: item => item.getSelectorLabels(),
+ [columnId.replicas]: item => item.getReplicas(),
+ [columnId.replicasDesired]: item => item.getDesiredReplicas(),
+ }}
+ searchFilters={[
+ item => item.getSearchFields(),
+ item => item.getSelectorLabels(),
+ ]}
+ renderHeaderTitle="Replication Controllers"
+ renderTableHeader={[
+ { title: "Name", className: "name", sortBy: columnId.name, id: columnId.name },
+ {
+ title: "Namespace",
+ className: "namespace",
+ sortBy: columnId.namespace,
+ id: columnId.namespace,
+ },
+ { title: "Replicas", sortBy: columnId.replicas, id: columnId.replicas },
+ {
+ title: "Desired Replicas",
+ sortBy: columnId.replicasDesired,
+ id: columnId.replicasDesired,
+ },
+ {
+ title: "Selector",
+ sortBy: columnId.selector,
+ id: columnId.selector,
+ },
+ ]}
+ renderTableContents={item => [
+ item.getName(),
+ ,
+ item.getReplicas(),
+ item.getDesiredReplicas(),
+ item.getSelectorLabels().map(label => ()),
+ ]}
+ />
+
+ );
+});
+
+export const ReplicationControllers = withInjectables(NonInjectedReplicationControllers, {
+ getProps: (di, props) => ({
+ ...props,
+ store: di.inject(replicationControllerStoreInjectable),
+ }),
+});
diff --git a/packages/core/src/renderer/components/kube-object-details/kube-object-detail-items/implementations/replication-controller-detail-item.injectable.ts b/packages/core/src/renderer/components/kube-object-details/kube-object-detail-items/implementations/replication-controller-detail-item.injectable.ts
new file mode 100644
index 0000000000..df14d6cc35
--- /dev/null
+++ b/packages/core/src/renderer/components/kube-object-details/kube-object-detail-items/implementations/replication-controller-detail-item.injectable.ts
@@ -0,0 +1,35 @@
+/**
+ * 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 { kubeObjectDetailItemInjectionToken } from "../kube-object-detail-item-injection-token";
+import { computed } from "mobx";
+import {
+ kubeObjectMatchesToKindAndApiVersion,
+} from "../kube-object-matches-to-kind-and-api-version";
+import currentKubeObjectInDetailsInjectable from "../../current-kube-object-in-details.injectable";
+import { ReplicationControllerDetails } from "../../../+workloads-replicationcontrollers";
+
+const replicationControllerDetailItemInjectable = getInjectable({
+ id: "replication-controller-detail-item",
+
+ instantiate(di) {
+ const kubeObject = di.inject(currentKubeObjectInDetailsInjectable);
+
+ return {
+ Component: ReplicationControllerDetails,
+ enabled: computed(() => isReplicationController(kubeObject.value.get()?.object)),
+ orderNumber: 10,
+ };
+ },
+
+ injectionToken: kubeObjectDetailItemInjectionToken,
+});
+
+export const isReplicationController = kubeObjectMatchesToKindAndApiVersion(
+ "ReplicationController",
+ ["v1"],
+);
+
+export default replicationControllerDetailItemInjectable;
diff --git a/packages/core/src/renderer/utils/rbac.ts b/packages/core/src/renderer/utils/rbac.ts
index 00135a6492..18748bcfac 100644
--- a/packages/core/src/renderer/utils/rbac.ts
+++ b/packages/core/src/renderer/utils/rbac.ts
@@ -27,6 +27,7 @@ export const ResourceNames: Record = {
"deployments": "Deployments",
"statefulsets": "Stateful Sets",
"replicasets": "Replica Sets",
+ "replicationcontrollers": "Replication Controllers",
"jobs": "Jobs",
"cronjobs": "Cron Jobs",
"endpoints": "Endpoints",
From 4bf72742fd93b04e3aec7f9864ccce0bd36745b9 Mon Sep 17 00:00:00 2001
From: Janne Savolainen
Date: Thu, 16 Feb 2023 14:49:43 +0200
Subject: [PATCH 2/8] Fix configuration shown release details being stale
(#7174)
Signed-off-by: Janne Savolainen
---
...wing-details-for-helm-release.test.ts.snap | 2086 ++++++++++++++++-
.../showing-details-for-helm-release.test.ts | 91 +-
.../release-details-content.tsx | 6 +-
3 files changed, 2170 insertions(+), 13 deletions(-)
diff --git a/packages/core/src/features/helm-releases/__snapshots__/showing-details-for-helm-release.test.ts.snap b/packages/core/src/features/helm-releases/__snapshots__/showing-details-for-helm-release.test.ts.snap
index 86e80acc4c..c36ac69784 100644
--- a/packages/core/src/features/helm-releases/__snapshots__/showing-details-for-helm-release.test.ts.snap
+++ b/packages/core/src/features/helm-releases/__snapshots__/showing-details-for-helm-release.test.ts.snap
@@ -5818,7 +5818,7 @@ exports[`showing details for helm release given application is started when navi
@@ -7100,7 +7100,7 @@ exports[`showing details for helm release given application is started when navi
@@ -8382,7 +8382,7 @@ exports[`showing details for helm release given application is started when navi
@@ -9469,7 +9469,7 @@ exports[`showing details for helm release given application is started when navi
@@ -10557,7 +10557,7 @@ exports[`showing details for helm release given application is started when navi
@@ -11840,7 +11840,7 @@ exports[`showing details for helm release given application is started when navi
@@ -17047,3 +17047,2077 @@ exports[`showing details for helm release given application is started when navi
+
+
+
+
+
+
+
+
+
+ close
+
+
+
+ Close
+
+
+
+
+
+
+
+
+
+
+
+
+
+ some-other-name
+
+
+ content_copy
+
+
+
+ Copy
+
+
+
+
+ close
+
+
+
+ Close
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ close
+
+
+
+ Close
+
+
+
+
+
+
+
+
+
+
+
+
+
+ some-other-name
+
+
+ content_copy
+
+
+
+ Copy
+
+
+
+
+ close
+
+
+
+ Close
+
+
+
+
+
+
+