mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add 'onClickDetailIcon' event when user clicks the icon detail panel
Signed-off-by: Hung-Han (Henry) Chen <chenhungh@gmail.com>
This commit is contained in:
parent
e2f59781c8
commit
b9c485d0af
@ -39,6 +39,10 @@ export class GeneralEntity extends CatalogEntity<CatalogEntityMetadata, CatalogE
|
|||||||
navigate(this.spec.path);
|
navigate(this.spec.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClickDetailIcon() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
public onSettingsOpen(): void {
|
public onSettingsOpen(): void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,6 +100,12 @@ export class KubernetesCluster extends CatalogEntity<KubernetesClusterMetadata,
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClickDetailIcon(context: CatalogEntityActionContext) {
|
||||||
|
catalogCategoryRegistry
|
||||||
|
.getCategoryForEntity<KubernetesClusterCategory>(this)
|
||||||
|
?.emit("onClickDetailIcon", this, context);
|
||||||
|
}
|
||||||
|
|
||||||
async onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
async onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
||||||
if (!this.metadata.source || this.metadata.source === "local") {
|
if (!this.metadata.source || this.metadata.source === "local") {
|
||||||
context.menuItems.push({
|
context.menuItems.push({
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CatalogCategory, CatalogEntity, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
|
import { CatalogCategory, CatalogEntity, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityActionContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
|
||||||
import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
|
import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
|
||||||
import { productName } from "../vars";
|
import { productName } from "../vars";
|
||||||
import { WeblinkStore } from "../weblink-store";
|
import { WeblinkStore } from "../weblink-store";
|
||||||
@ -46,6 +46,12 @@ export class WebLink extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClickDetailIcon(context: CatalogEntityActionContext) {
|
||||||
|
catalogCategoryRegistry
|
||||||
|
.getCategoryForEntity<WebLinkCategory>(this)
|
||||||
|
?.emit("onClickDetailIcon", this, context);
|
||||||
|
}
|
||||||
|
|
||||||
async onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
async onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
||||||
if (this.metadata.source === "local") {
|
if (this.metadata.source === "local") {
|
||||||
context.menuItems.push({
|
context.menuItems.push({
|
||||||
|
|||||||
@ -59,6 +59,7 @@ export interface CatalogCategoryEvents {
|
|||||||
load: () => void;
|
load: () => void;
|
||||||
catalogAddMenu: (context: CatalogEntityAddMenuContext) => void;
|
catalogAddMenu: (context: CatalogEntityAddMenuContext) => void;
|
||||||
contextMenuOpen: (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void;
|
contextMenuOpen: (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void;
|
||||||
|
onClickDetailIcon: (entity: CatalogEntity, context: CatalogEntityActionContext) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class CatalogCategory extends (EventEmitter as new () => TypedEmitter<CatalogCategoryEvents>) {
|
export abstract class CatalogCategory extends (EventEmitter as new () => TypedEmitter<CatalogCategoryEvents>) {
|
||||||
@ -230,7 +231,21 @@ export abstract class CatalogEntity<
|
|||||||
return this.metadata.name;
|
return this.metadata.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger when user click on the icon in details panel
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* Priority < this.onClickDetailIcon, if this.onClickDetailIcon presents, onRun won't be called.
|
||||||
|
*/
|
||||||
public abstract onRun?(context: CatalogEntityActionContext): void | Promise<void>;
|
public abstract onRun?(context: CatalogEntityActionContext): void | Promise<void>;
|
||||||
public abstract onContextMenuOpen(context: CatalogEntityContextMenuContext): void | Promise<void>;
|
public abstract onContextMenuOpen(context: CatalogEntityContextMenuContext): void | Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger when user click on the icon in details panel
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* Priority > this.onRun, if presents, onRun won't be called.
|
||||||
|
*/
|
||||||
|
public abstract onClickDetailIcon?(context: CatalogEntityActionContext): void;
|
||||||
public abstract onSettingsOpen(context: CatalogEntitySettingsContext): void | Promise<void>;
|
public abstract onSettingsOpen(context: CatalogEntitySettingsContext): void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,10 @@ class InvalidEntity extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onClickDetailIcon(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
public onSettingsOpen(): void {
|
public onSettingsOpen(): void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
112
src/renderer/components/+catalog/catalog-entity-details.test.tsx
Normal file
112
src/renderer/components/+catalog/catalog-entity-details.test.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
import React from "react";
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import userEvent from "@testing-library/user-event";
|
||||||
|
import { CatalogEntityDetails } from "./catalog-entity-details";
|
||||||
|
import { CatalogEntityItem } from "./catalog-entity-item";
|
||||||
|
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
||||||
|
|
||||||
|
// avoid TypeError: window.requestIdleCallback is not a function
|
||||||
|
import { mockWindow } from "../../../../__mocks__/windowMock";
|
||||||
|
|
||||||
|
mockWindow();
|
||||||
|
|
||||||
|
describe("<CatalogEntityDetails />", () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
CatalogEntityDetailRegistry.createInstance();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("trigger onRun when click on detail panel icon", () => {
|
||||||
|
const onRun = jest.fn();
|
||||||
|
|
||||||
|
const item = new CatalogEntityItem({
|
||||||
|
enabled: true,
|
||||||
|
apiVersion: "",
|
||||||
|
kind: "",
|
||||||
|
metadata: {
|
||||||
|
uid: "",
|
||||||
|
name: "",
|
||||||
|
labels: {},
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "",
|
||||||
|
},
|
||||||
|
spec: {},
|
||||||
|
getId: () => "",
|
||||||
|
getName: () => "",
|
||||||
|
onContextMenuOpen: () => {},
|
||||||
|
onSettingsOpen: () => {},
|
||||||
|
onRun,
|
||||||
|
});
|
||||||
|
|
||||||
|
render(
|
||||||
|
<CatalogEntityDetails
|
||||||
|
item={item}
|
||||||
|
hideDetails={() => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon"));
|
||||||
|
|
||||||
|
expect(onRun).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prioritize onClickDetailIcon over onRun", () => {
|
||||||
|
const onRun = jest.fn();
|
||||||
|
const onClickDetailIcon = jest.fn();
|
||||||
|
|
||||||
|
const item = new CatalogEntityItem({
|
||||||
|
enabled: true,
|
||||||
|
apiVersion: "",
|
||||||
|
kind: "",
|
||||||
|
metadata: {
|
||||||
|
uid: "",
|
||||||
|
name: "",
|
||||||
|
labels: {},
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "",
|
||||||
|
},
|
||||||
|
spec: {},
|
||||||
|
getId: () => "",
|
||||||
|
getName: () => "",
|
||||||
|
onContextMenuOpen: () => {},
|
||||||
|
onSettingsOpen: () => {},
|
||||||
|
onRun,
|
||||||
|
onClickDetailIcon,
|
||||||
|
});
|
||||||
|
|
||||||
|
render(
|
||||||
|
<CatalogEntityDetails
|
||||||
|
item={item}
|
||||||
|
hideDetails={() => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon"));
|
||||||
|
|
||||||
|
expect(onRun).toHaveBeenCalledTimes(0);
|
||||||
|
expect(onClickDetailIcon).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ import { Icon } from "../icon";
|
|||||||
import { CatalogEntityDrawerMenu } from "./catalog-entity-drawer-menu";
|
import { CatalogEntityDrawerMenu } from "./catalog-entity-drawer-menu";
|
||||||
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
||||||
import { HotbarIcon } from "../hotbar/hotbar-icon";
|
import { HotbarIcon } from "../hotbar/hotbar-icon";
|
||||||
import type { CatalogEntityItem } from "./catalog-entity.store";
|
import type { CatalogEntityItem } from "./catalog-entity-item";
|
||||||
import { isDevelopment } from "../../../common/vars";
|
import { isDevelopment } from "../../../common/vars";
|
||||||
|
|
||||||
interface Props<T extends CatalogEntity> {
|
interface Props<T extends CatalogEntity> {
|
||||||
@ -68,8 +68,16 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Pro
|
|||||||
material={item.entity.spec.icon?.material}
|
material={item.entity.spec.icon?.material}
|
||||||
background={item.entity.spec.icon?.background}
|
background={item.entity.spec.icon?.background}
|
||||||
disabled={!item?.enabled}
|
disabled={!item?.enabled}
|
||||||
onClick={() => item.onRun(catalogEntityRunContext)}
|
onClick={() => {
|
||||||
size={128} />
|
if (typeof item.entity.onClickDetailIcon === "function") {
|
||||||
|
item.onClickDetailIcon(catalogEntityRunContext);
|
||||||
|
} else {
|
||||||
|
item.onRun(catalogEntityRunContext);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
size={128}
|
||||||
|
data-testid="detail-panel-hot-bar-icon"
|
||||||
|
/>
|
||||||
{item?.enabled && (
|
{item?.enabled && (
|
||||||
<div className="IconHint">
|
<div className="IconHint">
|
||||||
Click to open
|
Click to open
|
||||||
|
|||||||
129
src/renderer/components/+catalog/catalog-entity-item.tsx
Normal file
129
src/renderer/components/+catalog/catalog-entity-item.tsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
import styles from "./catalog.module.css";
|
||||||
|
import React from "react";
|
||||||
|
import { action, computed } from "mobx";
|
||||||
|
import type { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity";
|
||||||
|
import type { ItemObject } from "../../../common/item.store";
|
||||||
|
import { Badge } from "../badge";
|
||||||
|
import { navigation } from "../../navigation";
|
||||||
|
import { searchUrlParam } from "../input";
|
||||||
|
import { makeCss } from "../../../common/utils/makeCss";
|
||||||
|
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||||
|
|
||||||
|
const css = makeCss(styles);
|
||||||
|
|
||||||
|
export class CatalogEntityItem<T extends CatalogEntity> implements ItemObject {
|
||||||
|
constructor(public entity: T) {}
|
||||||
|
|
||||||
|
get kind() {
|
||||||
|
return this.entity.kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
get apiVersion() {
|
||||||
|
return this.entity.apiVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.entity.metadata.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName() {
|
||||||
|
return this.entity.metadata.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.entity.metadata.uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get phase() {
|
||||||
|
return this.entity.status.phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
get enabled() {
|
||||||
|
return this.entity.status.enabled ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get labels() {
|
||||||
|
return KubeObject.stringifyLabels(this.entity.metadata.labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLabelBadges(onClick?: React.MouseEventHandler<any>) {
|
||||||
|
return this.labels
|
||||||
|
.map(label => (
|
||||||
|
<Badge
|
||||||
|
className={css.badge}
|
||||||
|
key={label}
|
||||||
|
label={label}
|
||||||
|
title={label}
|
||||||
|
onClick={(event) => {
|
||||||
|
navigation.searchParams.set(searchUrlParam.name, label);
|
||||||
|
onClick?.(event);
|
||||||
|
event.stopPropagation();
|
||||||
|
}}
|
||||||
|
expandable={false}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
get source() {
|
||||||
|
return this.entity.metadata.source || "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
get searchFields() {
|
||||||
|
return [
|
||||||
|
this.name,
|
||||||
|
this.id,
|
||||||
|
this.phase,
|
||||||
|
`source=${this.source}`,
|
||||||
|
...this.labels,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger when user click on the icon in details panel
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* Priority < this.onClickDetailIcon, if this.onClickDetailIcon presents, onRun won't be called.
|
||||||
|
*/
|
||||||
|
onRun(ctx: CatalogEntityActionContext) {
|
||||||
|
this.entity.onRun(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async onContextMenuOpen(ctx: any) {
|
||||||
|
return this.entity.onContextMenuOpen(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger when user click on the icon in details panel
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* Priority > this.onRun, if presents, onRun won't be called.
|
||||||
|
*/
|
||||||
|
onClickDetailIcon(ctx: CatalogEntityActionContext) {
|
||||||
|
this.entity.onClickDetailIcon?.(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,103 +19,13 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import styles from "./catalog.module.css";
|
import { computed, IReactionDisposer, makeObservable, observable, reaction } from "mobx";
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from "mobx";
|
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
||||||
import type { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity";
|
import type { CatalogEntity } from "../../api/catalog-entity";
|
||||||
import { ItemObject, ItemStore } from "../../../common/item.store";
|
import { ItemStore } from "../../../common/item.store";
|
||||||
import { CatalogCategory, catalogCategoryRegistry } from "../../../common/catalog";
|
import { CatalogCategory, catalogCategoryRegistry } from "../../../common/catalog";
|
||||||
import { autoBind } from "../../../common/utils";
|
import { autoBind } from "../../../common/utils";
|
||||||
import { Badge } from "../badge";
|
import { CatalogEntityItem } from "./catalog-entity-item";
|
||||||
import { navigation } from "../../navigation";
|
|
||||||
import { searchUrlParam } from "../input";
|
|
||||||
import { makeCss } from "../../../common/utils/makeCss";
|
|
||||||
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
|
||||||
|
|
||||||
const css = makeCss(styles);
|
|
||||||
|
|
||||||
export class CatalogEntityItem<T extends CatalogEntity> implements ItemObject {
|
|
||||||
constructor(public entity: T) {}
|
|
||||||
|
|
||||||
get kind() {
|
|
||||||
return this.entity.kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
get apiVersion() {
|
|
||||||
return this.entity.apiVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name() {
|
|
||||||
return this.entity.metadata.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
getName() {
|
|
||||||
return this.entity.metadata.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get id() {
|
|
||||||
return this.entity.metadata.uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed get phase() {
|
|
||||||
return this.entity.status.phase;
|
|
||||||
}
|
|
||||||
|
|
||||||
get enabled() {
|
|
||||||
return this.entity.status.enabled ?? true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get labels() {
|
|
||||||
return KubeObject.stringifyLabels(this.entity.metadata.labels);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLabelBadges(onClick?: React.MouseEventHandler<any>) {
|
|
||||||
return this.labels
|
|
||||||
.map(label => (
|
|
||||||
<Badge
|
|
||||||
className={css.badge}
|
|
||||||
key={label}
|
|
||||||
label={label}
|
|
||||||
title={label}
|
|
||||||
onClick={(event) => {
|
|
||||||
navigation.searchParams.set(searchUrlParam.name, label);
|
|
||||||
onClick?.(event);
|
|
||||||
event.stopPropagation();
|
|
||||||
}}
|
|
||||||
expandable={false}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
get source() {
|
|
||||||
return this.entity.metadata.source || "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
get searchFields() {
|
|
||||||
return [
|
|
||||||
this.name,
|
|
||||||
this.id,
|
|
||||||
this.phase,
|
|
||||||
`source=${this.source}`,
|
|
||||||
...this.labels,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
onRun(ctx: CatalogEntityActionContext) {
|
|
||||||
this.entity.onRun(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
async onContextMenuOpen(ctx: any) {
|
|
||||||
return this.entity.onContextMenuOpen(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CatalogEntityStore extends ItemStore<CatalogEntityItem<CatalogEntity>> {
|
export class CatalogEntityStore extends ItemStore<CatalogEntityItem<CatalogEntity>> {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
160
src/renderer/components/+catalog/catalog.test.tsx
Normal file
160
src/renderer/components/+catalog/catalog.test.tsx
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import userEvent from "@testing-library/user-event";
|
||||||
|
import { Catalog } from "./catalog";
|
||||||
|
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
||||||
|
import { createMemoryHistory } from "history";
|
||||||
|
import { mockWindow } from "../../../../__mocks__/windowMock";
|
||||||
|
import {
|
||||||
|
KubernetesCluster,
|
||||||
|
kubernetesClusterCategory,
|
||||||
|
} from "../../../common/catalog-entities/kubernetes-cluster";
|
||||||
|
import { CatalogEntityItem } from "./catalog-entity-item";
|
||||||
|
import { CatalogEntityStore } from "./catalog-entity.store";
|
||||||
|
|
||||||
|
mockWindow();
|
||||||
|
|
||||||
|
// avoid TypeError: Cannot read property 'getPath' of undefined
|
||||||
|
jest.mock("@electron/remote", () => {
|
||||||
|
return {
|
||||||
|
app: {
|
||||||
|
getPath: () => {
|
||||||
|
// avoid TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// avoid crashese in <CatalogMenu />
|
||||||
|
jest.mock("../../api/catalog-category-registry", () => {
|
||||||
|
return {
|
||||||
|
catalogCategoryRegistry: {
|
||||||
|
filteredItems: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("<Catalog />", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
CatalogEntityDetailRegistry.createInstance();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
// mock the return of getting CatalogEntityStore.selectedItem
|
||||||
|
jest
|
||||||
|
.spyOn(CatalogEntityStore.prototype, "selectedItem", "get")
|
||||||
|
.mockImplementation(() => {
|
||||||
|
const mockCluster = new KubernetesCluster({
|
||||||
|
metadata: {
|
||||||
|
uid: "",
|
||||||
|
name: "",
|
||||||
|
source: "",
|
||||||
|
labels: {},
|
||||||
|
distro: "",
|
||||||
|
kubeVersion: "",
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
kubeconfigPath: "",
|
||||||
|
kubeconfigContext: "",
|
||||||
|
icon: {},
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "disconnected",
|
||||||
|
reason: "",
|
||||||
|
message: "",
|
||||||
|
active: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const entityItem = new CatalogEntityItem(mockCluster);
|
||||||
|
|
||||||
|
return entityItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("emits ", () => {
|
||||||
|
const history = createMemoryHistory();
|
||||||
|
const mockLocation = {
|
||||||
|
pathname: "",
|
||||||
|
search: "",
|
||||||
|
state: "",
|
||||||
|
hash: "",
|
||||||
|
};
|
||||||
|
const mockMatch = {
|
||||||
|
params: {},
|
||||||
|
isExact: true,
|
||||||
|
path: "",
|
||||||
|
url: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<Catalog history={history} location={mockLocation} match={mockMatch} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = jest.spyOn(kubernetesClusterCategory, "emit");
|
||||||
|
|
||||||
|
userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon"));
|
||||||
|
|
||||||
|
expect(emit).toHaveBeenCalledTimes(1);
|
||||||
|
expect(emit.mock.calls).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
"onClickDetailIcon",
|
||||||
|
KubernetesCluster {
|
||||||
|
"apiVersion": "entity.k8slens.dev/v1alpha1",
|
||||||
|
"kind": "KubernetesCluster",
|
||||||
|
"metadata": Object {
|
||||||
|
"distro": "",
|
||||||
|
"kubeVersion": "",
|
||||||
|
"labels": Object {},
|
||||||
|
"name": "",
|
||||||
|
"source": "",
|
||||||
|
"uid": "",
|
||||||
|
},
|
||||||
|
"spec": Object {
|
||||||
|
"icon": Object {},
|
||||||
|
"kubeconfigContext": "",
|
||||||
|
"kubeconfigPath": "",
|
||||||
|
},
|
||||||
|
"status": Object {
|
||||||
|
"active": false,
|
||||||
|
"message": "",
|
||||||
|
"phase": "disconnected",
|
||||||
|
"reason": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"navigate": [Function],
|
||||||
|
"setCommandPaletteContext": [Function],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -25,7 +25,8 @@ import React from "react";
|
|||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { ItemListLayout } from "../item-object-list";
|
import { ItemListLayout } from "../item-object-list";
|
||||||
import { action, makeObservable, observable, reaction, runInAction, when } from "mobx";
|
import { action, makeObservable, observable, reaction, runInAction, when } from "mobx";
|
||||||
import { CatalogEntityItem, CatalogEntityStore } from "./catalog-entity.store";
|
import { CatalogEntityStore } from "./catalog-entity.store";
|
||||||
|
import type { CatalogEntityItem } from "./catalog-entity-item";
|
||||||
import { navigate } from "../../navigation";
|
import { navigate } from "../../navigation";
|
||||||
import { MenuItem, MenuActions } from "../menu";
|
import { MenuItem, MenuActions } from "../menu";
|
||||||
import { CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity";
|
import { CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity";
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user