mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Replace kube object menu registry with reactive solution (#4731)
Co-authored-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
0ce4e3d793
commit
ac42a6565f
5
__mocks__/monaco-editor.ts
Normal file
5
__mocks__/monaco-editor.ts
Normal file
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
export default {};
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
export type { StatusBarRegistration } from "../../renderer/components/cluster-manager/status-bar-registration";
|
||||
export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration";
|
||||
export type { AppPreferenceRegistration, AppPreferenceComponents } from "../../renderer/components/+preferences/app-preferences/app-preference-registration";
|
||||
export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry";
|
||||
export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../registries/kube-object-menu-registry";
|
||||
export type { KubeObjectStatusRegistration } from "../registries/kube-object-status-registry";
|
||||
export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps, PageComponents, PageTarget } from "../registries/page-registry";
|
||||
export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../registries/page-menu-registry";
|
||||
|
||||
@ -276,7 +276,6 @@ export class ExtensionLoader {
|
||||
const removeItems = [
|
||||
registries.ClusterPageRegistry.getInstance().add(extension.clusterPages, extension),
|
||||
registries.ClusterPageMenuRegistry.getInstance().add(extension.clusterPageMenus, extension),
|
||||
registries.KubeObjectMenuRegistry.getInstance().add(extension.kubeObjectMenuItems),
|
||||
registries.KubeObjectDetailRegistry.getInstance().add(extension.kubeObjectDetailItems),
|
||||
registries.KubeObjectStatusRegistry.getInstance().add(extension.kubeObjectStatusTexts),
|
||||
registries.WorkloadsOverviewDetailRegistry.getInstance().add(extension.kubeWorkloadsOverviewItems),
|
||||
|
||||
@ -19,6 +19,7 @@ import type { AppPreferenceRegistration } from "../renderer/components/+preferen
|
||||
import type { AdditionalCategoryColumnRegistration } from "../renderer/components/+catalog/custom-category-columns";
|
||||
import type { CustomCategoryViewRegistration } from "../renderer/components/+catalog/custom-views";
|
||||
import type { StatusBarRegistration } from "../renderer/components/cluster-manager/status-bar-registration";
|
||||
import type { KubeObjectMenuRegistration } from "../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration";
|
||||
|
||||
export class LensRendererExtension extends LensExtension {
|
||||
globalPages: registries.PageRegistration[] = [];
|
||||
@ -29,7 +30,7 @@ export class LensRendererExtension extends LensExtension {
|
||||
entitySettings: registries.EntitySettingRegistration[] = [];
|
||||
statusBarItems: StatusBarRegistration[] = [];
|
||||
kubeObjectDetailItems: registries.KubeObjectDetailRegistration[] = [];
|
||||
kubeObjectMenuItems: registries.KubeObjectMenuRegistration[] = [];
|
||||
kubeObjectMenuItems: KubeObjectMenuRegistration[] = [];
|
||||
kubeWorkloadsOverviewItems: registries.WorkloadsOverviewDetailRegistration[] = [];
|
||||
commands: CommandRegistration[] = [];
|
||||
welcomeMenus: WelcomeMenuRegistration[] = [];
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
export * from "./page-registry";
|
||||
export * from "./page-menu-registry";
|
||||
export * from "./kube-object-detail-registry";
|
||||
export * from "./kube-object-menu-registry";
|
||||
export * from "./kube-object-status-registry";
|
||||
export * from "./entity-setting-registry";
|
||||
export * from "./catalog-entity-detail-registry";
|
||||
|
||||
@ -73,9 +73,6 @@ export async function bootstrap(di: DependencyInjectionContainer) {
|
||||
logger.info(`${logPrefix} initializing EntitySettingsRegistry`);
|
||||
initializers.initEntitySettingsRegistry();
|
||||
|
||||
logger.info(`${logPrefix} initializing KubeObjectMenuRegistry`);
|
||||
initializers.initKubeObjectMenuRegistry();
|
||||
|
||||
logger.info(`${logPrefix} initializing KubeObjectDetailRegistry`);
|
||||
initializers.initKubeObjectDetailRegistry();
|
||||
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import type { KubeObjectMenuProps } from "../../kube-object-menu";
|
||||
import type { ServiceAccount } from "../../../../common/k8s-api/endpoints";
|
||||
import { MenuItem } from "../../menu";
|
||||
import { openServiceAccountKubeConfig } from "../../kubeconfig-dialog";
|
||||
import { Icon } from "../../icon";
|
||||
|
||||
export function ServiceAccountMenu(props: KubeObjectMenuProps<ServiceAccount>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<MenuItem onClick={() => openServiceAccountKubeConfig(object)}>
|
||||
<Icon material="insert_drive_file" tooltip="Kubeconfig File" interactive={toolbar} />
|
||||
<span className="title">Kubeconfig</span>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
@ -8,13 +8,8 @@ import "./view.scss";
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import type { RouteComponentProps } from "react-router";
|
||||
import type { ServiceAccount } from "../../../../common/k8s-api/endpoints/service-accounts.api";
|
||||
import { Icon } from "../../icon";
|
||||
import { KubeObjectListLayout } from "../../kube-object-list-layout";
|
||||
import { KubeObjectStatusIcon } from "../../kube-object-status-icon";
|
||||
import type { KubeObjectMenuProps } from "../../kube-object-menu";
|
||||
import { openServiceAccountKubeConfig } from "../../kubeconfig-dialog";
|
||||
import { MenuItem } from "../../menu";
|
||||
import { CreateServiceAccountDialog } from "./create-dialog";
|
||||
import { serviceAccountsStore } from "./store";
|
||||
import type { ServiceAccountsRouteParams } from "../../../../common/routes";
|
||||
@ -69,13 +64,3 @@ export class ServiceAccounts extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export function ServiceAccountMenu(props: KubeObjectMenuProps<ServiceAccount>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<MenuItem onClick={() => openServiceAccountKubeConfig(object)}>
|
||||
<Icon material="insert_drive_file" tooltip="Kubeconfig File" interactive={toolbar} />
|
||||
<span className="title">Kubeconfig</span>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import { CronJob, cronJobApi } from "../../../common/k8s-api/endpoints";
|
||||
import { MenuItem } from "../menu";
|
||||
import { CronJobTriggerDialog } from "./cronjob-trigger-dialog";
|
||||
import { Icon } from "../icon";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { Notifications } from "../notifications";
|
||||
|
||||
export function CronJobMenu(props: KubeObjectMenuProps<CronJob>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => CronJobTriggerDialog.open(object)}>
|
||||
<Icon material="play_circle_filled" tooltip="Trigger" interactive={toolbar}/>
|
||||
<span className="title">Trigger</span>
|
||||
</MenuItem>
|
||||
|
||||
{object.isSuspend() ?
|
||||
<MenuItem onClick={() => ConfirmDialog.open({
|
||||
ok: async () => {
|
||||
try {
|
||||
await cronJobApi.resume({ namespace: object.getNs(), name: object.getName() });
|
||||
} catch (err) {
|
||||
Notifications.error(err);
|
||||
}
|
||||
},
|
||||
labelOk: `Resume`,
|
||||
message: (
|
||||
<p>
|
||||
Resume CronJob <b>{object.getName()}</b>?
|
||||
</p>),
|
||||
})}>
|
||||
<Icon material="play_circle_outline" tooltip="Resume" interactive={toolbar}/>
|
||||
<span className="title">Resume</span>
|
||||
</MenuItem>
|
||||
|
||||
: <MenuItem onClick={() => ConfirmDialog.open({
|
||||
ok: async () => {
|
||||
try {
|
||||
await cronJobApi.suspend({ namespace: object.getNs(), name: object.getName() });
|
||||
} catch (err) {
|
||||
Notifications.error(err);
|
||||
}
|
||||
},
|
||||
labelOk: `Suspend`,
|
||||
message: (
|
||||
<p>
|
||||
Suspend CronJob <b>{object.getName()}</b>?
|
||||
</p>),
|
||||
})}>
|
||||
<Icon material="pause_circle_filled" tooltip="Suspend" interactive={toolbar}/>
|
||||
<span className="title">Suspend</span>
|
||||
</MenuItem>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -8,18 +8,11 @@ import "./cronjobs.scss";
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { RouteComponentProps } from "react-router";
|
||||
import { CronJob, cronJobApi } from "../../../common/k8s-api/endpoints/cron-job.api";
|
||||
import { MenuItem } from "../menu";
|
||||
import { Icon } from "../icon";
|
||||
import { cronJobStore } from "./cronjob.store";
|
||||
import { jobStore } from "../+workloads-jobs/job.store";
|
||||
import { eventStore } from "../+events/event.store";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
import { CronJobTriggerDialog } from "./cronjob-trigger-dialog";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { ConfirmDialog } from "../confirm-dialog/confirm-dialog";
|
||||
import { Notifications } from "../notifications/notifications";
|
||||
import type { CronJobsRouteParams } from "../../../common/routes";
|
||||
import moment from "moment";
|
||||
|
||||
@ -87,53 +80,3 @@ export class CronJobs extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export function CronJobMenu(props: KubeObjectMenuProps<CronJob>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => CronJobTriggerDialog.open(object)}>
|
||||
<Icon material="play_circle_filled" tooltip="Trigger" interactive={toolbar}/>
|
||||
<span className="title">Trigger</span>
|
||||
</MenuItem>
|
||||
|
||||
{object.isSuspend() ?
|
||||
<MenuItem onClick={() => ConfirmDialog.open({
|
||||
ok: async () => {
|
||||
try {
|
||||
await cronJobApi.resume({ namespace: object.getNs(), name: object.getName() });
|
||||
} catch (err) {
|
||||
Notifications.error(err);
|
||||
}
|
||||
},
|
||||
labelOk: `Resume`,
|
||||
message: (
|
||||
<p>
|
||||
Resume CronJob <b>{object.getName()}</b>?
|
||||
</p>),
|
||||
})}>
|
||||
<Icon material="play_circle_outline" tooltip="Resume" interactive={toolbar}/>
|
||||
<span className="title">Resume</span>
|
||||
</MenuItem>
|
||||
|
||||
: <MenuItem onClick={() => ConfirmDialog.open({
|
||||
ok: async () => {
|
||||
try {
|
||||
await cronJobApi.suspend({ namespace: object.getNs(), name: object.getName() });
|
||||
} catch (err) {
|
||||
Notifications.error(err);
|
||||
}
|
||||
},
|
||||
labelOk: `Suspend`,
|
||||
message: (
|
||||
<p>
|
||||
Suspend CronJob <b>{object.getName()}</b>?
|
||||
</p>),
|
||||
})}>
|
||||
<Icon material="pause_circle_filled" tooltip="Suspend" interactive={toolbar}/>
|
||||
<span className="title">Suspend</span>
|
||||
</MenuItem>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import { Deployment, deploymentApi } from "../../../common/k8s-api/endpoints";
|
||||
import { MenuItem } from "../menu";
|
||||
import { DeploymentScaleDialog } from "./deployment-scale-dialog";
|
||||
import { Icon } from "../icon";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { Notifications } from "../notifications";
|
||||
|
||||
export function DeploymentMenu(props: KubeObjectMenuProps<Deployment>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => DeploymentScaleDialog.open(object)}>
|
||||
<Icon material="open_with" tooltip="Scale" interactive={toolbar}/>
|
||||
<span className="title">Scale</span>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => ConfirmDialog.open({
|
||||
ok: async () =>
|
||||
{
|
||||
try {
|
||||
await deploymentApi.restart({
|
||||
namespace: object.getNs(),
|
||||
name: object.getName(),
|
||||
});
|
||||
} catch (err) {
|
||||
Notifications.error(err);
|
||||
}
|
||||
},
|
||||
labelOk: `Restart`,
|
||||
message: (
|
||||
<p>
|
||||
Are you sure you want to restart deployment <b>{object.getName()}</b>?
|
||||
</p>
|
||||
),
|
||||
})}>
|
||||
<Icon material="autorenew" tooltip="Restart" interactive={toolbar}/>
|
||||
<span className="title">Restart</span>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -8,12 +8,7 @@ import "./deployments.scss";
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { RouteComponentProps } from "react-router";
|
||||
import { Deployment, deploymentApi } from "../../../common/k8s-api/endpoints";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import { MenuItem } from "../menu";
|
||||
import { Icon } from "../icon";
|
||||
import { DeploymentScaleDialog } from "./deployment-scale-dialog";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import type { Deployment } from "../../../common/k8s-api/endpoints";
|
||||
import { deploymentStore } from "./deployments.store";
|
||||
import { eventStore } from "../+events/event.store";
|
||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
@ -21,7 +16,6 @@ import { cssNames } from "../../utils";
|
||||
import kebabCase from "lodash/kebabCase";
|
||||
import orderBy from "lodash/orderBy";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { Notifications } from "../notifications";
|
||||
import type { DeploymentsRouteParams } from "../../../common/routes";
|
||||
|
||||
enum columnId {
|
||||
@ -95,38 +89,3 @@ export class Deployments extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function DeploymentMenu(props: KubeObjectMenuProps<Deployment>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => DeploymentScaleDialog.open(object)}>
|
||||
<Icon material="open_with" tooltip="Scale" interactive={toolbar}/>
|
||||
<span className="title">Scale</span>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => ConfirmDialog.open({
|
||||
ok: async () =>
|
||||
{
|
||||
try {
|
||||
await deploymentApi.restart({
|
||||
namespace: object.getNs(),
|
||||
name: object.getName(),
|
||||
});
|
||||
} catch (err) {
|
||||
Notifications.error(err);
|
||||
}
|
||||
},
|
||||
labelOk: `Restart`,
|
||||
message: (
|
||||
<p>
|
||||
Are you sure you want to restart deployment <b>{object.getName()}</b>?
|
||||
</p>
|
||||
),
|
||||
})}>
|
||||
<Icon material="autorenew" tooltip="Restart" interactive={toolbar}/>
|
||||
<span className="title">Restart</span>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import type { ReplicaSet } from "../../../common/k8s-api/endpoints";
|
||||
import { MenuItem } from "../menu";
|
||||
import { ReplicaSetScaleDialog } from "./replicaset-scale-dialog";
|
||||
import { Icon } from "../icon";
|
||||
|
||||
export function ReplicaSetMenu(props: KubeObjectMenuProps<ReplicaSet>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => ReplicaSetScaleDialog.open(object)}>
|
||||
<Icon material="open_with" tooltip="Scale" interactive={toolbar}/>
|
||||
<span className="title">Scale</span>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -7,15 +7,10 @@ import "./replicasets.scss";
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { ReplicaSet } from "../../../common/k8s-api/endpoints";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import { replicaSetStore } from "./replicasets.store";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import type { RouteComponentProps } from "react-router";
|
||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
import { MenuItem } from "../menu/menu";
|
||||
import { Icon } from "../icon/icon";
|
||||
import { ReplicaSetScaleDialog } from "./replicaset-scale-dialog";
|
||||
import type { ReplicaSetsRouteParams } from "../../../common/routes";
|
||||
import { eventStore } from "../+events/event.store";
|
||||
|
||||
@ -75,15 +70,3 @@ export class ReplicaSets extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export function ReplicaSetMenu(props: KubeObjectMenuProps<ReplicaSet>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => ReplicaSetScaleDialog.open(object)}>
|
||||
<Icon material="open_with" tooltip="Scale" interactive={toolbar}/>
|
||||
<span className="title">Scale</span>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import type { StatefulSet } from "../../../common/k8s-api/endpoints";
|
||||
import { MenuItem } from "../menu";
|
||||
import { StatefulSetScaleDialog } from "./statefulset-scale-dialog";
|
||||
import { Icon } from "../icon";
|
||||
|
||||
export function StatefulSetMenu(props: KubeObjectMenuProps<StatefulSet>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => StatefulSetScaleDialog.open(object)}>
|
||||
<Icon material="open_with" tooltip="Scale" interactive={toolbar}/>
|
||||
<span className="title">Scale</span>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -12,12 +12,8 @@ import type { StatefulSet } from "../../../common/k8s-api/endpoints";
|
||||
import { podsStore } from "../+workloads-pods/pods.store";
|
||||
import { statefulSetStore } from "./statefulset.store";
|
||||
import { eventStore } from "../+events/event.store";
|
||||
import type { KubeObjectMenuProps } from "../kube-object-menu";
|
||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { StatefulSetScaleDialog } from "./statefulset-scale-dialog";
|
||||
import { MenuItem } from "../menu/menu";
|
||||
import { Icon } from "../icon/icon";
|
||||
import type { StatefulSetsRouteParams } from "../../../common/routes";
|
||||
|
||||
enum columnId {
|
||||
@ -76,16 +72,3 @@ export class StatefulSets extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function StatefulSetMenu(props: KubeObjectMenuProps<StatefulSet>) {
|
||||
const { object, toolbar } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={() => StatefulSetScaleDialog.open(object)}>
|
||||
<Icon material="open_with" tooltip="Scale" interactive={toolbar}/>
|
||||
<span className="title">Scale</span>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,21 +2,36 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { KubeObjectMenuRegistry } from "../../../../../extensions/registries";
|
||||
import { conforms, includes, eq } from "lodash/fp";
|
||||
import type { KubeObject } from "../../../../../common/k8s-api/kube-object";
|
||||
import type { LensRendererExtension } from "../../../../../extensions/lens-renderer-extension";
|
||||
import { staticKubeObjectMenuItems as staticMenuItems } from "./static-kube-object-menu-items";
|
||||
|
||||
interface Dependencies {
|
||||
extensions: LensRendererExtension[];
|
||||
kubeObject: KubeObject;
|
||||
}
|
||||
|
||||
export const getKubeObjectMenuItems = ({
|
||||
kubeObjectMenuRegistry,
|
||||
extensions,
|
||||
kubeObject,
|
||||
}: {
|
||||
kubeObjectMenuRegistry: KubeObjectMenuRegistry;
|
||||
kubeObject: KubeObject;
|
||||
}) => {
|
||||
}: Dependencies) => {
|
||||
if (!kubeObject) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return kubeObjectMenuRegistry
|
||||
.getItemsForKind(kubeObject.kind, kubeObject.apiVersion)
|
||||
const extensionMenuItems = extensions.flatMap(
|
||||
(extension) => extension.kubeObjectMenuItems,
|
||||
);
|
||||
|
||||
return [...staticMenuItems, ...extensionMenuItems]
|
||||
.filter(
|
||||
conforms({
|
||||
kind: eq(kubeObject.kind),
|
||||
apiVersions: includes(kubeObject.apiVersion),
|
||||
}),
|
||||
)
|
||||
|
||||
.map((item) => item.components.MenuItem);
|
||||
};
|
||||
|
||||
|
||||
@ -3,15 +3,15 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import kubeObjectMenuRegistryInjectable from "./kube-object-menu-registry.injectable";
|
||||
|
||||
import { getKubeObjectMenuItems } from "./get-kube-object-menu-items";
|
||||
import type { KubeObject } from "../../../../../common/k8s-api/kube-object";
|
||||
import rendererExtensionsInjectable from "../../../../../extensions/renderer-extensions.injectable";
|
||||
|
||||
const kubeObjectMenuItemsInjectable = getInjectable({
|
||||
instantiate: (di, { kubeObject }: { kubeObject: KubeObject }) =>
|
||||
getKubeObjectMenuItems({
|
||||
kubeObjectMenuRegistry: di.inject(kubeObjectMenuRegistryInjectable),
|
||||
extensions: di.inject(rendererExtensionsInjectable).get(),
|
||||
kubeObject,
|
||||
}),
|
||||
|
||||
|
||||
@ -4,10 +4,15 @@
|
||||
*/
|
||||
|
||||
import type React from "react";
|
||||
import { BaseRegistry } from "./base-registry";
|
||||
import type { KubeObject } from "../../../../../common/k8s-api/kube-object";
|
||||
|
||||
export interface KubeObjectMenuItemProps {
|
||||
object: KubeObject;
|
||||
toolbar?: boolean;
|
||||
}
|
||||
|
||||
export interface KubeObjectMenuComponents {
|
||||
MenuItem: React.ComponentType<any>;
|
||||
MenuItem: React.ComponentType<KubeObjectMenuItemProps>;
|
||||
}
|
||||
|
||||
export interface KubeObjectMenuRegistration {
|
||||
@ -15,11 +20,3 @@ export interface KubeObjectMenuRegistration {
|
||||
apiVersions: string[];
|
||||
components: KubeObjectMenuComponents;
|
||||
}
|
||||
|
||||
export class KubeObjectMenuRegistry extends BaseRegistry<KubeObjectMenuRegistration> {
|
||||
getItemsForKind(kind: string, apiVersion: string) {
|
||||
return this.getItems().filter((item) => {
|
||||
return item.kind === kind && item.apiVersions.includes(apiVersion);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { KubeObjectMenuRegistry } from "../../../../../extensions/registries";
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
|
||||
const kubeObjectMenuRegistryInjectable = getInjectable({
|
||||
instantiate: () => KubeObjectMenuRegistry.getInstance(),
|
||||
lifecycle: lifecycleEnum.singleton,
|
||||
});
|
||||
|
||||
export default kubeObjectMenuRegistryInjectable;
|
||||
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { ServiceAccountMenu } from "../../../+user-management/+service-accounts/service-account-menu";
|
||||
import { CronJobMenu } from "../../../+workloads-cronjobs/cron-job-menu";
|
||||
import { DeploymentMenu } from "../../../+workloads-deployments/deployment-menu";
|
||||
import { ReplicaSetMenu } from "../../../+workloads-replicasets/replica-set-menu";
|
||||
import { StatefulSetMenu } from "../../../+workloads-statefulsets/stateful-set-menu";
|
||||
|
||||
export const staticKubeObjectMenuItems = [
|
||||
{
|
||||
kind: "ServiceAccount",
|
||||
apiVersions: ["v1"],
|
||||
components: {
|
||||
MenuItem: ServiceAccountMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "CronJob",
|
||||
apiVersions: ["batch/v1beta1"],
|
||||
components: {
|
||||
MenuItem: CronJobMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "Deployment",
|
||||
apiVersions: ["apps/v1"],
|
||||
components: {
|
||||
MenuItem: DeploymentMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "ReplicaSet",
|
||||
apiVersions: ["apps/v1"],
|
||||
components: {
|
||||
MenuItem: ReplicaSetMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "StatefulSet",
|
||||
apiVersions: ["apps/v1"],
|
||||
components: {
|
||||
MenuItem: StatefulSetMenu,
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -2,76 +2,108 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { screen } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import type { ConfigurableDependencyInjectionContainer } from "@ogre-tools/injectable";
|
||||
import type { KubeObjectMenuRegistration } from "../../../extensions/registries";
|
||||
import { KubeObjectMenuRegistry } from "../../../extensions/registries";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import asyncFn, { AsyncFnMock } from "@async-fn/jest";
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
|
||||
import clusterInjectable from "./dependencies/cluster.injectable";
|
||||
import hideDetailsInjectable from "./dependencies/hide-details.injectable";
|
||||
import createEditResourceTabInjectable from "../dock/edit-resource/edit-resource-tab.injectable";
|
||||
import kubeObjectMenuRegistryInjectable from "./dependencies/kube-object-menu-items/kube-object-menu-registry.injectable";
|
||||
import { DiRender, renderFor } from "../test-utils/renderFor";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import type { ApiManager } from "../../../common/k8s-api/api-manager";
|
||||
import apiManagerInjectable from "./dependencies/api-manager.injectable";
|
||||
import { KubeObjectMenu } from "./index";
|
||||
import type { KubeObjectMenuRegistration } from "./dependencies/kube-object-menu-items/kube-object-menu-registration";
|
||||
import { computed } from "mobx";
|
||||
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
||||
import createEditResourceTabInjectable from "../dock/edit-resource/edit-resource-tab.injectable";
|
||||
|
||||
// TODO: Make tooltips free of side effects by making it deterministic
|
||||
jest.mock("../tooltip");
|
||||
|
||||
class SomeTestExtension extends LensRendererExtension {
|
||||
constructor(
|
||||
kubeObjectMenuItems: KubeObjectMenuRegistration[],
|
||||
) {
|
||||
super({
|
||||
id: "some-id",
|
||||
absolutePath: "irrelevant",
|
||||
isBundled: false,
|
||||
isCompatible: false,
|
||||
isEnabled: false,
|
||||
manifest: { name: "some-id", version: "some-version" },
|
||||
manifestPath: "irrelevant",
|
||||
});
|
||||
|
||||
this.kubeObjectMenuItems = kubeObjectMenuItems;
|
||||
}
|
||||
}
|
||||
|
||||
describe("kube-object-menu", () => {
|
||||
let di: ConfigurableDependencyInjectionContainer;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
const MenuItemComponent: React.FC = () => <li>Some menu item</li>;
|
||||
|
||||
const kubeObjectMenuItems = [
|
||||
{
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-kind",
|
||||
components: { MenuItem: MenuItemComponent },
|
||||
},
|
||||
|
||||
{
|
||||
apiVersions: ["some-unrelated-api-version"],
|
||||
kind: "some-kind",
|
||||
components: { MenuItem: MenuItemComponent },
|
||||
},
|
||||
|
||||
{
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-unrelated-kind",
|
||||
components: { MenuItem: MenuItemComponent },
|
||||
},
|
||||
];
|
||||
|
||||
const someTestExtension = new SomeTestExtension(kubeObjectMenuItems);
|
||||
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
// TODO: Remove global shared state
|
||||
KubeObjectMenuRegistry.resetInstance();
|
||||
KubeObjectMenuRegistry.createInstance();
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
di.override(clusterInjectable, () => ({
|
||||
name: "Some name",
|
||||
}) as Cluster);
|
||||
di.override(rendererExtensionsInjectable, () =>
|
||||
computed(() => [someTestExtension]),
|
||||
);
|
||||
|
||||
di.override(apiManagerInjectable, () => ({
|
||||
getStore: api => void api,
|
||||
}) as ApiManager);
|
||||
await di.runSetups();
|
||||
|
||||
di.override(
|
||||
clusterInjectable,
|
||||
() =>
|
||||
({
|
||||
name: "Some name",
|
||||
} as Cluster),
|
||||
);
|
||||
|
||||
di.override(
|
||||
apiManagerInjectable,
|
||||
() =>
|
||||
({
|
||||
getStore: (api) => void api,
|
||||
} as ApiManager),
|
||||
);
|
||||
|
||||
di.override(hideDetailsInjectable, () => () => {});
|
||||
|
||||
di.override(createEditResourceTabInjectable, () => () => "irrelevant");
|
||||
|
||||
addDynamicMenuItem({
|
||||
di,
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-kind",
|
||||
});
|
||||
|
||||
addDynamicMenuItem({
|
||||
di,
|
||||
apiVersions: ["some-unrelated-api-version"],
|
||||
kind: "some-kind",
|
||||
});
|
||||
|
||||
addDynamicMenuItem({
|
||||
di,
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-unrelated-kind",
|
||||
});
|
||||
});
|
||||
|
||||
it("given no cluster, does not crash", () => {
|
||||
@ -242,25 +274,3 @@ describe("kube-object-menu", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const addDynamicMenuItem = ({
|
||||
di,
|
||||
apiVersions,
|
||||
kind,
|
||||
}: {
|
||||
di: ConfigurableDependencyInjectionContainer;
|
||||
apiVersions: string[];
|
||||
kind: string;
|
||||
}) => {
|
||||
const MenuItemComponent: React.FC = () => <li>Some menu item</li>;
|
||||
|
||||
const dynamicMenuItemStub: KubeObjectMenuRegistration = {
|
||||
apiVersions,
|
||||
kind,
|
||||
components: { MenuItem: MenuItemComponent },
|
||||
};
|
||||
|
||||
const kubeObjectMenuRegistry = di.inject(kubeObjectMenuRegistryInjectable);
|
||||
|
||||
kubeObjectMenuRegistry.add([dynamicMenuItemStub]);
|
||||
};
|
||||
|
||||
@ -8,7 +8,6 @@ export * from "./catalog";
|
||||
export * from "./entity-settings-registry";
|
||||
export * from "./ipc";
|
||||
export * from "./kube-object-detail-registry";
|
||||
export * from "./kube-object-menu-registry";
|
||||
export * from "./registries";
|
||||
export * from "./workloads-overview-detail-registry";
|
||||
export * from "./catalog-category-registry";
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { KubeObjectMenuRegistry } from "../../extensions/registries";
|
||||
import { ServiceAccountMenu } from "../components/+user-management/+service-accounts";
|
||||
import { CronJobMenu } from "../components/+workloads-cronjobs";
|
||||
import { DeploymentMenu } from "../components/+workloads-deployments";
|
||||
import { ReplicaSetMenu } from "../components/+workloads-replicasets";
|
||||
import { StatefulSetMenu } from "../components/+workloads-statefulsets";
|
||||
|
||||
export function initKubeObjectMenuRegistry() {
|
||||
KubeObjectMenuRegistry.getInstance()
|
||||
.add([
|
||||
{
|
||||
kind: "ServiceAccount",
|
||||
apiVersions: ["v1"],
|
||||
components: {
|
||||
MenuItem: ServiceAccountMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "CronJob",
|
||||
apiVersions: ["batch/v1beta1"],
|
||||
components: {
|
||||
MenuItem: CronJobMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "Deployment",
|
||||
apiVersions: ["apps/v1"],
|
||||
components: {
|
||||
MenuItem: DeploymentMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "ReplicaSet",
|
||||
apiVersions: ["apps/v1"],
|
||||
components: {
|
||||
MenuItem: ReplicaSetMenu,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "StatefulSet",
|
||||
apiVersions: ["apps/v1"],
|
||||
components: {
|
||||
MenuItem: StatefulSetMenu,
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
@ -12,7 +12,6 @@ export function initRegistries() {
|
||||
registries.EntitySettingRegistry.createInstance();
|
||||
registries.GlobalPageRegistry.createInstance();
|
||||
registries.KubeObjectDetailRegistry.createInstance();
|
||||
registries.KubeObjectMenuRegistry.createInstance();
|
||||
registries.KubeObjectStatusRegistry.createInstance();
|
||||
registries.WorkloadsOverviewDetailRegistry.createInstance();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user