From 54e874f646896c9f22a278cf8d0f58d267fdbbb2 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 16 Feb 2023 14:48:24 +0200 Subject: [PATCH] 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",