mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
New resource view: Network -> Ingress Classes (#6808)
* added backbone for k8s-api/endpoints/ingress-class.api Signed-off-by: Roman <ixrock@gmail.com> * added ingress-class store, naming clean up Signed-off-by: Roman <ixrock@gmail.com> * navigate to ingress-classses injectable Signed-off-by: Roman <ixrock@gmail.com> * added new sidebar item: "Network -> Ingress Classes" Signed-off-by: Roman <ixrock@gmail.com> * added explicit returning type for `ingresses-sidebar-items.injectable` Signed-off-by: Roman <ixrock@gmail.com> * added initial ingress-class table-view + magic route-component.injectable Signed-off-by: Roman <ixrock@gmail.com> * fix: show loaded items from api into IngressClasses view Signed-off-by: Roman <ixrock@gmail.com> * fix: new bugs after master merging (with conflicts!), looks like breaking change if those apis where exported Signed-off-by: Roman <ixrock@gmail.com> * fix lint Signed-off-by: Roman <ixrock@gmail.com> * added icon-marker to see default ingress class in the list Signed-off-by: Roman <ixrock@gmail.com> * Page refresh is broken in development mode #6818 (upcoming fix) Signed-off-by: Roman <ixrock@gmail.com> * added "set as default" menu action for ingress classes Signed-off-by: Roman <ixrock@gmail.com> * fix: consistent sidebar items order by janne's request Signed-off-by: Roman <ixrock@gmail.com> * chore, fix lint Signed-off-by: Roman <ixrock@gmail.com> * fix: incorrect icons layout in ingress-class details Signed-off-by: Roman <ixrock@gmail.com> * some fixes, improved items search by values from `spec.parameters.*` Signed-off-by: Roman <ixrock@gmail.com> * fix: duplicating/overcaching items with each page visiting (Nnetwork -> Ingress classes) Signed-off-by: Roman <ixrock@gmail.com> * handling IngressClass drawer details Signed-off-by: Roman <ixrock@gmail.com> * fixes: remove duplicating / allow editing IngressClass items (due api's "namespaced=true") Signed-off-by: Roman <ixrock@gmail.com> * fix: incorrect `apiName` for `front-end-routing/cluster/network/ingress-class` Signed-off-by: Roman <ixrock@gmail.com> * fix: IngressClass proper metadata typing Signed-off-by: Roman <ixrock@gmail.com> * allow to mark as default IngressClass from menu item Signed-off-by: Roman <ixrock@gmail.com> * fix lint Signed-off-by: Roman <ixrock@gmail.com> * fixes & responding to comments Signed-off-by: Roman <ixrock@gmail.com> Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
e5a67d535f
commit
1456e1e597
@ -2,6 +2,5 @@
|
|||||||
<profile version="1.0">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<option name="myName" value="Project Default" />
|
||||||
<inspection_tool class="ES6PreferShortImport" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
<inspection_tool class="ES6PreferShortImport" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
||||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
||||||
</profile>
|
</profile>
|
||||||
</component>
|
</component>
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="EslintConfiguration">
|
|
||||||
<option name="fix-on-save" value="true" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* 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 { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
|
||||||
|
import {
|
||||||
|
shouldShowResourceInjectionToken,
|
||||||
|
} from "../../../../../cluster-store/allowed-resources-injection-token";
|
||||||
|
|
||||||
|
const ingressClassesesRouteInjectable = getInjectable({
|
||||||
|
id: "ingress-classes-route",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const isEnabled = di.inject(shouldShowResourceInjectionToken, {
|
||||||
|
apiName: "ingressclasses",
|
||||||
|
group: "networking.k8s.io",
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: "/ingress-classes",
|
||||||
|
clusterFrame: true,
|
||||||
|
isEnabled,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: frontEndRouteInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ingressClassesesRouteInjectable;
|
||||||
@ -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 { navigateToRouteInjectionToken } from "../../../../navigate-to-route-injection-token";
|
||||||
|
import ingressClassesesRouteInjectable from "./ingress-classeses-route.injectable";
|
||||||
|
|
||||||
|
const navigateToIngressesInjectable = getInjectable({
|
||||||
|
id: "navigate-to-ingress-classes",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||||
|
const route = di.inject(ingressClassesesRouteInjectable);
|
||||||
|
|
||||||
|
return () => navigateToRoute(route);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default navigateToIngressesInjectable;
|
||||||
@ -18,6 +18,7 @@ export * from "./endpoint.api";
|
|||||||
export * from "./events.api";
|
export * from "./events.api";
|
||||||
export * from "./horizontal-pod-autoscaler.api";
|
export * from "./horizontal-pod-autoscaler.api";
|
||||||
export * from "./ingress.api";
|
export * from "./ingress.api";
|
||||||
|
export * from "./ingress-class.api";
|
||||||
export * from "./job.api";
|
export * from "./job.api";
|
||||||
export * from "./lease.api";
|
export * from "./lease.api";
|
||||||
export * from "./limit-range.api";
|
export * from "./limit-range.api";
|
||||||
|
|||||||
18
src/common/k8s-api/endpoints/ingress-class.api.injectable.ts
Normal file
18
src/common/k8s-api/endpoints/ingress-class.api.injectable.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 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 { IngressClassApi } from "./ingress-class.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
|
||||||
|
const ingressClassApiInjectable = getInjectable({
|
||||||
|
id: "ingress-class-api",
|
||||||
|
instantiate: () => {
|
||||||
|
return new IngressClassApi();
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ingressClassApiInjectable;
|
||||||
101
src/common/k8s-api/endpoints/ingress-class.api.ts
Normal file
101
src/common/k8s-api/endpoints/ingress-class.api.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { KubeObjectMetadata, KubeObjectScope } from "../kube-object";
|
||||||
|
import { KubeObject } from "../kube-object";
|
||||||
|
import type { ResourceDescriptor } from "../kube-api";
|
||||||
|
import { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
|
export class IngressClassApi extends KubeApi<IngressClass> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
objectConstructor: IngressClass,
|
||||||
|
checkPreferredVersion: true,
|
||||||
|
fallbackApiBases: ["/apis/extensions/v1beta1/ingressclasses"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setAsDefault({ name }: ResourceDescriptor, isDefault = true) {
|
||||||
|
const reqUrl = this.formatUrlForNotListing({ name });
|
||||||
|
|
||||||
|
return this.request.patch(reqUrl, {
|
||||||
|
data: {
|
||||||
|
metadata: {
|
||||||
|
annotations: {
|
||||||
|
[IngressClass.ANNOTATION_IS_DEFAULT]: JSON.stringify(isDefault),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/strategic-merge-patch+json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#ingressclass-v1-networking-k8s-io
|
||||||
|
export type IngressClassMetadata = KubeObjectMetadata<KubeObjectScope.Cluster> & {
|
||||||
|
"name": string;
|
||||||
|
"labels"?: {
|
||||||
|
[name: string]: string | undefined;
|
||||||
|
"app.kubernetes.io/component"?: "controller";
|
||||||
|
};
|
||||||
|
"annotations"?: {
|
||||||
|
[name: string]: string | undefined;
|
||||||
|
"ingressclass.kubernetes.io/is-default-class"?: "true";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IngressClassParametersReference {
|
||||||
|
"apiGroup": string; // k8s.example.net
|
||||||
|
"scope": "Namespace" | "Cluster";
|
||||||
|
"kind": "ClusterIngressParameter" | "IngressParameter";
|
||||||
|
"name": string; // external-config-1
|
||||||
|
"namespace"?: string; // namespaced for IngressClass must be defined in `spec.parameters.namespace` instead of `metadata.namespace` (!)
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IngressClassSpec {
|
||||||
|
controller: string; // "example.com/ingress-controller"
|
||||||
|
parameters?: IngressClassParametersReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IngressClassStatus {
|
||||||
|
}
|
||||||
|
|
||||||
|
export class IngressClass extends KubeObject<IngressClassMetadata, IngressClassStatus, IngressClassSpec> {
|
||||||
|
static readonly kind = "IngressClass";
|
||||||
|
static readonly namespaced = false;
|
||||||
|
static readonly apiBase = "/apis/networking.k8s.io/v1/ingressclasses";
|
||||||
|
static readonly ANNOTATION_IS_DEFAULT = "ingressclass.kubernetes.io/is-default-class";
|
||||||
|
|
||||||
|
getController(): string {
|
||||||
|
return this.spec.controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCtrlApiGroup() {
|
||||||
|
return this.spec?.parameters?.apiGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCtrlScope() {
|
||||||
|
return this.spec?.parameters?.scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCtrlNs() {
|
||||||
|
return this.spec?.parameters?.namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCtrlKind() {
|
||||||
|
return this.spec?.parameters?.kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCtrlName() {
|
||||||
|
return this.spec?.parameters?.name as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isDefault() {
|
||||||
|
return this.metadata.annotations?.[IngressClass.ANNOTATION_IS_DEFAULT] === "true";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
export type KubeResource =
|
export type KubeResource =
|
||||||
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" |
|
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" |
|
||||||
"secrets" | "configmaps" | "ingresses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
|
"secrets" | "configmaps" | "ingresses" | "ingressclasses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
|
||||||
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" |
|
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" |
|
||||||
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" |
|
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" |
|
||||||
"priorityclasses" | "runtimeclasses" |
|
"priorityclasses" | "runtimeclasses" |
|
||||||
@ -87,6 +87,11 @@ export const apiResourceRecord: Record<KubeResource, KubeApiResourceData> = {
|
|||||||
group: "networking.k8s.io",
|
group: "networking.k8s.io",
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
},
|
},
|
||||||
|
ingressclasses: {
|
||||||
|
kind: "IngressClass",
|
||||||
|
group: "networking.k8s.io",
|
||||||
|
namespaced: false,
|
||||||
|
},
|
||||||
jobs: {
|
jobs: {
|
||||||
kind: "Job",
|
kind: "Job",
|
||||||
group: "batch",
|
group: "batch",
|
||||||
|
|||||||
@ -115,7 +115,8 @@ export type { PodDisruptionBudgetStore as PodDisruptionBudgetsStore } from "../.
|
|||||||
export type { PriorityClassStore as PriorityClassStoreStore } from "../../renderer/components/+config-priority-classes/store";
|
export type { PriorityClassStore as PriorityClassStoreStore } from "../../renderer/components/+config-priority-classes/store";
|
||||||
export type { ServiceStore } from "../../renderer/components/+network-services/store";
|
export type { ServiceStore } from "../../renderer/components/+network-services/store";
|
||||||
export type { EndpointsStore as EndpointStore } from "../../renderer/components/+network-endpoints/store";
|
export type { EndpointsStore as EndpointStore } from "../../renderer/components/+network-endpoints/store";
|
||||||
export type { IngressStore } from "../../renderer/components/+network-ingresses/store";
|
export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress-store";
|
||||||
|
export type { IngressClassStore } from "../../renderer/components/+network-ingresses/ingress-class-store";
|
||||||
export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/store";
|
export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/store";
|
||||||
export type { PersistentVolumeStore as PersistentVolumesStore } from "../../renderer/components/+storage-volumes/store";
|
export type { PersistentVolumeStore as PersistentVolumesStore } from "../../renderer/components/+storage-volumes/store";
|
||||||
export type { PersistentVolumeClaimStore as VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/store";
|
export type { PersistentVolumeClaimStore as VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/store";
|
||||||
|
|||||||
@ -5,3 +5,5 @@
|
|||||||
|
|
||||||
export * from "./ingresses";
|
export * from "./ingresses";
|
||||||
export * from "./ingress-details";
|
export * from "./ingress-details";
|
||||||
|
export * from "./ingress-classes";
|
||||||
|
export * from "./ingress-class-details";
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.IngressClassDetails {
|
||||||
|
--titles-color: var(--textColorSecondary);
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import styles from "./ingress-class-details.module.scss";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||||
|
import type { IngressClass } from "../../../common/k8s-api/endpoints";
|
||||||
|
import type { KubeObjectDetailsProps } from "../kube-object-details";
|
||||||
|
import { Badge } from "../badge";
|
||||||
|
|
||||||
|
export interface IngressClassDetailsProps extends KubeObjectDetailsProps<IngressClass> {
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class NonInjectedIngressDetails extends React.Component<IngressClassDetailsProps> {
|
||||||
|
renderParameters() {
|
||||||
|
const { object: ingressClass } = this.props;
|
||||||
|
|
||||||
|
if (!ingressClass.spec.parameters) return;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DrawerTitle>Parameters</DrawerTitle>
|
||||||
|
<DrawerItem name="Name">
|
||||||
|
{ingressClass.getCtrlName()}
|
||||||
|
</DrawerItem>
|
||||||
|
<DrawerItem name="Namespace">
|
||||||
|
{ingressClass.getCtrlNs()}
|
||||||
|
</DrawerItem>
|
||||||
|
<DrawerItem name="Scope">
|
||||||
|
{ingressClass.getCtrlScope()}
|
||||||
|
</DrawerItem>
|
||||||
|
<DrawerItem name="Kind">
|
||||||
|
{ingressClass.getCtrlKind()}
|
||||||
|
</DrawerItem>
|
||||||
|
<DrawerItem name="API Group">
|
||||||
|
{ingressClass.getCtrlApiGroup()}
|
||||||
|
</DrawerItem>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { object: ingressClass } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.IngressClassDetails}>
|
||||||
|
<DrawerItem name="Controller">
|
||||||
|
<Badge label={ingressClass.getController()} />
|
||||||
|
</DrawerItem>
|
||||||
|
{this.renderParameters()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IngressClassDetails = withInjectables<{}, IngressClassDetailsProps>(NonInjectedIngressDetails, {
|
||||||
|
getProps: (di, props) => (props),
|
||||||
|
});
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import { computed } from "mobx";
|
||||||
|
import type {
|
||||||
|
KubeObjectMenuItemComponent,
|
||||||
|
KubeObjectMenuItem,
|
||||||
|
} from "../kube-object-menu/kube-object-menu-item-injection-token";
|
||||||
|
import {
|
||||||
|
kubeObjectMenuItemInjectionToken,
|
||||||
|
} from "../kube-object-menu/kube-object-menu-item-injection-token";
|
||||||
|
import { ingressClassSetDefaultInjectable } from "./ingress-class-set-default.injectable";
|
||||||
|
import { MenuItem } from "../menu";
|
||||||
|
import type { IngressClass } from "../../../common/k8s-api/endpoints/ingress-class.api";
|
||||||
|
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import hideDetailsInjectable from "../kube-detail-params/hide-details.injectable";
|
||||||
|
|
||||||
|
export interface IngressClassMenuProps extends KubeObjectMenuProps<IngressClass> {
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Dependencies {
|
||||||
|
setDefault: (item: IngressClass) => void;
|
||||||
|
hideDetails: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NonInjectedIngressClassMenu(
|
||||||
|
{
|
||||||
|
object,
|
||||||
|
toolbar,
|
||||||
|
setDefault,
|
||||||
|
hideDetails,
|
||||||
|
}: IngressClassMenuProps & Dependencies) {
|
||||||
|
|
||||||
|
function markItemAsDefaultIngressClass() {
|
||||||
|
setDefault(object);
|
||||||
|
hideDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MenuItem onClick={markItemAsDefaultIngressClass}>
|
||||||
|
<Icon
|
||||||
|
material="star"
|
||||||
|
tooltip="Set as default"
|
||||||
|
interactive={toolbar} />
|
||||||
|
<span className="title">Set as default</span>
|
||||||
|
</MenuItem>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IngressClassMenu = withInjectables<Dependencies, IngressClassMenuProps>(NonInjectedIngressClassMenu, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
setDefault: di.inject(ingressClassSetDefaultInjectable),
|
||||||
|
hideDetails: di.inject(hideDetailsInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const ingressClassMenuInjectable = getInjectable({
|
||||||
|
id: "ingress-class-kube-object-menu",
|
||||||
|
|
||||||
|
instantiate(): KubeObjectMenuItem {
|
||||||
|
return {
|
||||||
|
kind: "IngressClass",
|
||||||
|
apiVersions: ["networking.k8s.io/v1"],
|
||||||
|
Component: IngressClassMenu as KubeObjectMenuItemComponent,
|
||||||
|
enabled: computed(() => true),
|
||||||
|
orderNumber: 30,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeObjectMenuItemInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ingressClassMenuInjectable;
|
||||||
@ -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 {
|
||||||
|
routeSpecificComponentInjectionToken,
|
||||||
|
} from "../../routes/route-specific-component-injection-token";
|
||||||
|
import ingressClassesesRouteInjectable
|
||||||
|
from "../../../common/front-end-routing/routes/cluster/network/ingress-class/ingress-classeses-route.injectable";
|
||||||
|
import { IngressClasses } from "./ingress-classes";
|
||||||
|
|
||||||
|
const ingressClassesRouteComponentInjectable = getInjectable({
|
||||||
|
id: "ingress-classes-route-component",
|
||||||
|
|
||||||
|
instantiate: (di) => ({
|
||||||
|
route: di.inject(ingressClassesesRouteInjectable),
|
||||||
|
Component: IngressClasses,
|
||||||
|
}),
|
||||||
|
|
||||||
|
injectionToken: routeSpecificComponentInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ingressClassesRouteComponentInjectable;
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import type { IngressClass } from "../../../common/k8s-api/endpoints/ingress-class.api";
|
||||||
|
import ingressClassApiInjectable
|
||||||
|
from "../../../common/k8s-api/endpoints/ingress-class.api.injectable";
|
||||||
|
import ingressClassStoreInjectable from "./ingress-class-store.injectable";
|
||||||
|
|
||||||
|
export const ingressClassSetDefaultInjectable = getInjectable({
|
||||||
|
id: "ingressClassSetDefaultInjectable",
|
||||||
|
|
||||||
|
instantiate(di) {
|
||||||
|
const api = di.inject(ingressClassApiInjectable);
|
||||||
|
const store = di.inject(ingressClassStoreInjectable);
|
||||||
|
|
||||||
|
return async (currentItem: IngressClass) => {
|
||||||
|
const defaultIngressClassesUpdate = store.items
|
||||||
|
.filter((item: IngressClass) => item.isDefault && currentItem !== item)
|
||||||
|
.map(item => api.setAsDefault({ name: item.getName() }, false));
|
||||||
|
|
||||||
|
await Promise.all(defaultIngressClassesUpdate);
|
||||||
|
await api.setAsDefault({ name: currentItem.getName() });
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import assert from "assert";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import {
|
||||||
|
kubeObjectStoreInjectionToken,
|
||||||
|
} from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||||
|
import ingressClassApiInjectable
|
||||||
|
from "../../../common/k8s-api/endpoints/ingress-class.api.injectable";
|
||||||
|
import { IngressClassStore } from "./ingress-class-store";
|
||||||
|
import clusterFrameContextForNamespacedResourcesInjectable
|
||||||
|
from "../../cluster-frame-context/for-namespaced-resources.injectable";
|
||||||
|
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
|
||||||
|
|
||||||
|
const ingressClassStoreInjectable = getInjectable({
|
||||||
|
id: "ingress-class-store",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
assert(di.inject(storesAndApisCanBeCreatedInjectable), "ingressClassStore is only available in certain environments");
|
||||||
|
|
||||||
|
const api = di.inject(ingressClassApiInjectable);
|
||||||
|
|
||||||
|
return new IngressClassStore({
|
||||||
|
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
|
||||||
|
}, api);
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeObjectStoreInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ingressClassStoreInjectable;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
||||||
|
import type { IngressClass, IngressClassApi } from "../../../common/k8s-api/endpoints/ingress-class.api";
|
||||||
|
|
||||||
|
export class IngressClassStore extends KubeObjectStore<IngressClass, IngressClassApi> {
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.IngressClasses {
|
||||||
|
:global(.TableCell) {
|
||||||
|
&.is_default {
|
||||||
|
:global(.Checkbox) {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.name {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.namespace {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.controller {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.apiGroup {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.scope {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.kind {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.Icon) {
|
||||||
|
&.set_default_icon {
|
||||||
|
filter: brightness(.75);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(1.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
112
src/renderer/components/+network-ingresses/ingress-classes.tsx
Normal file
112
src/renderer/components/+network-ingresses/ingress-classes.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import styles from "./ingress-classes.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 { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IngressClassStore } from "./ingress-class-store";
|
||||||
|
import ingressClassStoreInjectable from "./ingress-class-store.injectable";
|
||||||
|
import type { IngressClass } from "../../../common/k8s-api/endpoints/ingress-class.api";
|
||||||
|
import { cssNames } from "../../utils";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
|
||||||
|
enum columnId {
|
||||||
|
name = "name",
|
||||||
|
namespace = "namespace",
|
||||||
|
controller = "controller",
|
||||||
|
apiGroup = "apiGroup",
|
||||||
|
scope = "scope", // "Namespace" | "Cluster"
|
||||||
|
kind = "kind", // "ClusterIngressParameter" | "IngressParameter"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
store: IngressClassStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedIngressClasses = observer((props: Dependencies) => {
|
||||||
|
const {
|
||||||
|
store,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SiblingsInTabLayout>
|
||||||
|
<KubeObjectListLayout
|
||||||
|
isConfigurable
|
||||||
|
tableId="network_ingress_classess"
|
||||||
|
className={styles.IngressClasses}
|
||||||
|
store={store}
|
||||||
|
sortingCallbacks={{
|
||||||
|
[columnId.name]: (resource: IngressClass) => resource.getCtrlName(),
|
||||||
|
[columnId.namespace]: (resource: IngressClass) => resource.getCtrlNs(),
|
||||||
|
[columnId.controller]: (resource: IngressClass) => resource.getController(),
|
||||||
|
[columnId.apiGroup]: (resource: IngressClass) => resource.getCtrlApiGroup(),
|
||||||
|
[columnId.scope]: (resource: IngressClass) => resource.getCtrlScope(),
|
||||||
|
[columnId.kind]: (resource: IngressClass) => resource.getCtrlKind(),
|
||||||
|
}}
|
||||||
|
searchFilters={[
|
||||||
|
(resource: IngressClass) => resource.getSearchFields(),
|
||||||
|
(resource: IngressClass) => resource.getController(),
|
||||||
|
(resource: IngressClass) => resource.getCtrlApiGroup(),
|
||||||
|
(resource: IngressClass) => resource.getCtrlScope(),
|
||||||
|
(resource: IngressClass) => resource.getCtrlKind(),
|
||||||
|
]}
|
||||||
|
renderHeaderTitle="Ingress Classes"
|
||||||
|
renderTableHeader={[
|
||||||
|
{ title: "Name", className: styles.name, sortBy: columnId.name, id: columnId.name },
|
||||||
|
{
|
||||||
|
title: "Namespace",
|
||||||
|
className: styles.namespace,
|
||||||
|
sortBy: columnId.namespace,
|
||||||
|
id: columnId.namespace,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Controller",
|
||||||
|
className: styles.controller,
|
||||||
|
sortBy: columnId.controller,
|
||||||
|
id: columnId.controller,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "API Group",
|
||||||
|
className: styles.apiGroup,
|
||||||
|
sortBy: columnId.apiGroup,
|
||||||
|
id: columnId.apiGroup,
|
||||||
|
},
|
||||||
|
{ title: "Scope", className: styles.scope, sortBy: columnId.scope, id: columnId.scope },
|
||||||
|
{ title: "Kind", className: styles.kind, sortBy: columnId.kind, id: columnId.kind },
|
||||||
|
]}
|
||||||
|
renderTableContents={(ingressClass: IngressClass) => [
|
||||||
|
<div key={ingressClass.getId()} className={cssNames(styles.name)}>
|
||||||
|
{ingressClass.getName()}
|
||||||
|
{" "}
|
||||||
|
{ingressClass.isDefault && (
|
||||||
|
<Icon
|
||||||
|
small
|
||||||
|
material="star"
|
||||||
|
tooltip="Is default class for ingresses (when not specified)"
|
||||||
|
className={styles.set_default_icon}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>,
|
||||||
|
ingressClass.getCtrlNs(),
|
||||||
|
ingressClass.getController(),
|
||||||
|
ingressClass.getCtrlApiGroup(),
|
||||||
|
ingressClass.getCtrlScope(),
|
||||||
|
ingressClass.getCtrlKind(),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</SiblingsInTabLayout>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const IngressClasses = withInjectables<Dependencies>(NonInjectedIngressClasses, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
store: di.inject(ingressClassStoreInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -8,7 +8,7 @@ import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manag
|
|||||||
import ingressApiInjectable from "../../../common/k8s-api/endpoints/ingress.api.injectable";
|
import ingressApiInjectable from "../../../common/k8s-api/endpoints/ingress.api.injectable";
|
||||||
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
|
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
|
||||||
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
|
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
|
||||||
import { IngressStore } from "./store";
|
import { IngressStore } from "./ingress-store";
|
||||||
|
|
||||||
const ingressStoreInjectable = getInjectable({
|
const ingressStoreInjectable = getInjectable({
|
||||||
id: "ingress-store",
|
id: "ingress-store",
|
||||||
@ -3,32 +3,50 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
|
import ingressesRouteInjectable
|
||||||
import ingressesRouteInjectable from "../../../common/front-end-routing/routes/cluster/network/ingresses/ingresses-route.injectable";
|
from "../../../common/front-end-routing/routes/cluster/network/ingresses/ingresses-route.injectable";
|
||||||
import { sidebarItemsInjectionToken } from "../layout/sidebar-items.injectable";
|
import type {
|
||||||
|
SidebarItemRegistration } from "../layout/sidebar-items.injectable";
|
||||||
|
import {
|
||||||
|
sidebarItemsInjectionToken,
|
||||||
|
} from "../layout/sidebar-items.injectable";
|
||||||
import { networkSidebarItemId } from "../+network/network-sidebar-items.injectable";
|
import { networkSidebarItemId } from "../+network/network-sidebar-items.injectable";
|
||||||
import routeIsActiveInjectable from "../../routes/route-is-active.injectable";
|
import routeIsActiveInjectable from "../../routes/route-is-active.injectable";
|
||||||
import navigateToIngressesInjectable from "../../../common/front-end-routing/routes/cluster/network/ingresses/navigate-to-ingresses.injectable";
|
import navigateToIngressesInjectable
|
||||||
|
from "../../../common/front-end-routing/routes/cluster/network/ingresses/navigate-to-ingresses.injectable";
|
||||||
|
import ingressClassesesRouteInjectable
|
||||||
|
from "../../../common/front-end-routing/routes/cluster/network/ingress-class/ingress-classeses-route.injectable";
|
||||||
|
import navigateToIngressClassesInjectable
|
||||||
|
from "../../../common/front-end-routing/routes/cluster/network/ingress-class/navigate-to-ingress-classes.injectable";
|
||||||
|
|
||||||
const ingressesSidebarItemsInjectable = getInjectable({
|
const ingressesSidebarItemsInjectable = getInjectable({
|
||||||
id: "ingresses-sidebar-items",
|
id: "ingresses-sidebar-items",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di): IComputedValue<SidebarItemRegistration[]> => {
|
||||||
const route = di.inject(ingressesRouteInjectable);
|
const ingressRoute = di.inject(ingressesRouteInjectable);
|
||||||
const navigateToIngresses = di.inject(navigateToIngressesInjectable);
|
const ingressClassRoute = di.inject(ingressClassesesRouteInjectable);
|
||||||
const routeIsActive = di.inject(routeIsActiveInjectable, route);
|
|
||||||
|
|
||||||
return computed(() => [
|
return computed(() => [
|
||||||
{
|
{
|
||||||
id: "ingresses",
|
id: "ingresses",
|
||||||
parentId: networkSidebarItemId,
|
parentId: networkSidebarItemId,
|
||||||
title: "Ingresses",
|
title: "Ingresses",
|
||||||
onClick: navigateToIngresses,
|
onClick: di.inject(navigateToIngressesInjectable),
|
||||||
isActive: routeIsActive,
|
isActive: di.inject(routeIsActiveInjectable, ingressRoute),
|
||||||
isVisible: route.isEnabled,
|
isVisible: ingressRoute.isEnabled,
|
||||||
orderNumber: 30,
|
orderNumber: 30,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "ingressclasses",
|
||||||
|
parentId: networkSidebarItemId,
|
||||||
|
title: "Ingress Classes",
|
||||||
|
onClick: di.inject(navigateToIngressClassesInjectable),
|
||||||
|
isActive: di.inject(routeIsActiveInjectable, ingressClassRoute),
|
||||||
|
isVisible: ingressClassRoute.isEnabled,
|
||||||
|
orderNumber: 31,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -13,11 +13,11 @@ import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
|||||||
import { KubeObjectAge } from "../kube-object/age";
|
import { KubeObjectAge } from "../kube-object/age";
|
||||||
import { computeRouteDeclarations } from "../../../common/k8s-api/endpoints";
|
import { computeRouteDeclarations } from "../../../common/k8s-api/endpoints";
|
||||||
import { prevDefault } from "../../utils";
|
import { prevDefault } from "../../utils";
|
||||||
import type { IngressStore } from "./store";
|
import type { IngressStore } from "./ingress-store";
|
||||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||||
import ingressStoreInjectable from "./store.injectable";
|
import ingressStoreInjectable from "./ingress-store.injectable";
|
||||||
|
|
||||||
enum columnId {
|
enum columnId {
|
||||||
name = "name",
|
name = "name",
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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 { IngressClassDetails } from "../../../+network-ingresses";
|
||||||
|
import { kubeObjectMatchesToKindAndApiVersion } from "../kube-object-matches-to-kind-and-api-version";
|
||||||
|
import currentKubeObjectInDetailsInjectable from "../../current-kube-object-in-details.injectable";
|
||||||
|
|
||||||
|
const ingressClassDetailItemInjectable = getInjectable({
|
||||||
|
id: "ingress-class-detail-item",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const kubeObject = di.inject(currentKubeObjectInDetailsInjectable);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Component: IngressClassDetails,
|
||||||
|
enabled: computed(() => isIngressClass(kubeObject.value.get()?.object)),
|
||||||
|
orderNumber: 10,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeObjectDetailItemInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const isIngressClass = kubeObjectMatchesToKindAndApiVersion("IngressClass", [
|
||||||
|
"networking.k8s.io/v1",
|
||||||
|
"extensions/v1beta1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default ingressClassDetailItemInjectable;
|
||||||
@ -17,6 +17,7 @@ export const ResourceNames: Record<KubeResource, string> = {
|
|||||||
"secrets": "Secrets",
|
"secrets": "Secrets",
|
||||||
"configmaps": "Config Maps",
|
"configmaps": "Config Maps",
|
||||||
"ingresses": "Ingresses",
|
"ingresses": "Ingresses",
|
||||||
|
"ingressclasses": "Ingress Classes",
|
||||||
"networkpolicies": "Network Policies",
|
"networkpolicies": "Network Policies",
|
||||||
"persistentvolumeclaims": "Persistent Volume Claims",
|
"persistentvolumeclaims": "Persistent Volume Claims",
|
||||||
"persistentvolumes": "Persistent Volumes",
|
"persistentvolumes": "Persistent Volumes",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user