1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Remove unnecessary CatalogEntityItem (#4582)

* Remove unnecessary CatalogEntityItem

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Using simple notation to set search url params

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Fix styles file name

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

Co-authored-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Sebastian Malton 2021-12-24 05:49:34 -05:00 committed by GitHub
parent 2d279a6b99
commit 8082501bb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 219 additions and 110 deletions

View File

@ -20,9 +20,11 @@
*/
import { anyObject } from "jest-mock-extended";
import { merge } from "lodash";
import mockFs from "mock-fs";
import logger from "../../main/logger";
import { AppPaths } from "../app-paths";
import type { CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../catalog";
import { ClusterStore } from "../cluster-store";
import { HotbarStore } from "../hotbar-store";
@ -54,68 +56,58 @@ jest.mock("../../main/catalog/catalog-entity-registry", () => ({
},
}));
const testCluster = {
uid: "test",
name: "test",
function getMockCatalogEntity(data: Partial<CatalogEntityData> & CatalogEntityKindData): CatalogEntity {
return merge(data, {
getName: jest.fn(() => data.metadata?.name),
getId: jest.fn(() => data.metadata?.uid),
getSource: jest.fn(() => data.metadata?.source ?? "unknown"),
isEnabled: jest.fn(() => data.status?.enabled ?? true),
onContextMenuOpen: jest.fn(),
onSettingsOpen: jest.fn(),
metadata: {},
spec: {},
status: {},
}) as CatalogEntity;
}
const testCluster = getMockCatalogEntity({
apiVersion: "v1",
kind: "Cluster",
status: {
phase: "Running",
},
spec: {},
getName: jest.fn(),
getId: jest.fn(),
onDetailsOpen: jest.fn(),
onContextMenuOpen: jest.fn(),
onSettingsOpen: jest.fn(),
metadata: {
uid: "test",
name: "test",
labels: {},
},
};
});
const minikubeCluster = {
uid: "minikube",
name: "minikube",
const minikubeCluster = getMockCatalogEntity({
apiVersion: "v1",
kind: "Cluster",
status: {
phase: "Running",
},
spec: {},
getName: jest.fn(),
getId: jest.fn(),
onDetailsOpen: jest.fn(),
onContextMenuOpen: jest.fn(),
onSettingsOpen: jest.fn(),
metadata: {
uid: "minikube",
name: "minikube",
labels: {},
},
};
});
const awsCluster = {
uid: "aws",
name: "aws",
const awsCluster = getMockCatalogEntity({
apiVersion: "v1",
kind: "Cluster",
status: {
phase: "Running",
},
spec: {},
getName: jest.fn(),
getId: jest.fn(),
onDetailsOpen: jest.fn(),
onContextMenuOpen: jest.fn(),
onSettingsOpen: jest.fn(),
metadata: {
uid: "aws",
name: "aws",
labels: {},
},
};
});
jest.mock("electron", () => ({
app: {

View File

@ -38,14 +38,44 @@ export type CatalogEntityConstructor<Entity extends CatalogEntity> = (
);
export interface CatalogCategoryVersion<Entity extends CatalogEntity> {
/**
* The specific version that the associated constructor is for. This MUST be
* a DNS label and SHOULD be of the form `vN`, `vNalphaY`, or `vNbetaY` where
* `N` and `Y` are both integers greater than 0.
*
* Examples: The following are valid values for this field.
* - `v1`
* - `v1beta1`
* - `v1alpha2`
* - `v3beta2`
*/
name: string;
/**
* The constructor for the entities.
*/
entityClass: CatalogEntityConstructor<Entity>;
}
export interface CatalogCategorySpec {
/**
* The grouping for for the category. This MUST be a DNS label.
*/
group: string;
/**
* The specific versions of the constructors.
*
* NOTE: the field `.apiVersion` after construction MUST match `{.group}/{.versions.[] | .name}`.
* For example, if `group = "entity.k8slens.dev"` and there is an entry in `.versions` with
* `name = "v1alpha1"` then the resulting `.apiVersion` MUST be `entity.k8slens.dev/v1alpha1`
*/
versions: CatalogCategoryVersion<CatalogEntity>[];
names: {
/**
* The kind of entity that this category is for. This value MUST be a DNS
* label and MUST be equal to the `kind` fields that are produced by the
* `.versions.[] | .entityClass` fields.
*/
kind: string;
};
}
@ -114,6 +144,7 @@ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEm
export interface CatalogEntityMetadata {
uid: string;
name: string;
shortName?: string;
description?: string;
source?: string;
labels: Record<string, string>;
@ -211,7 +242,14 @@ export abstract class CatalogEntity<
Status extends CatalogEntityStatus = CatalogEntityStatus,
Spec extends CatalogEntitySpec = CatalogEntitySpec,
> implements CatalogEntityKindData {
/**
* The group and version of this class.
*/
public abstract readonly apiVersion: string;
/**
* A DNS label name of the entity.
*/
public abstract readonly kind: string;
@observable metadata: Metadata;
@ -225,14 +263,35 @@ export abstract class CatalogEntity<
this.spec = data.spec;
}
/**
* Get the UID of this entity
*/
public getId(): string {
return this.metadata.uid;
}
/**
* Get the name of this entity
*/
public getName(): string {
return this.metadata.name;
}
/**
* Get the specified source of this entity, defaulting to `"unknown"` if not
* provided
*/
public getSource(): string {
return this.metadata.source ?? "unknown";
}
/**
* Get if this entity is enabled.
*/
public isEnabled(): boolean {
return this.status.enabled ?? true;
}
public abstract onRun?(context: CatalogEntityActionContext): void | Promise<void>;
public abstract onContextMenuOpen(context: CatalogEntityContextMenuContext): void | Promise<void>;
public abstract onSettingsOpen(context: CatalogEntitySettingsContext): void | Promise<void>;

View File

@ -27,14 +27,15 @@ import type { CatalogCategory, CatalogEntity } from "../../../common/catalog";
import { Icon } from "../icon";
import { CatalogEntityDrawerMenu } from "./catalog-entity-drawer-menu";
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
import type { CatalogEntityItem } from "./catalog-entity-item";
import { isDevelopment } from "../../../common/vars";
import { cssNames } from "../../utils";
import { Avatar } from "../avatar";
import { getLabelBadges } from "./helpers";
interface Props<T extends CatalogEntity> {
item: CatalogEntityItem<T> | null | undefined;
entity: T;
hideDetails(): void;
onRun: () => void;
}
@observer
@ -47,32 +48,30 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Pro
}
}
renderContent(item: CatalogEntityItem<T>) {
const detailItems = CatalogEntityDetailRegistry.getInstance().getItemsForKind(item.kind, item.apiVersion);
const details = detailItems.map(({ components }, index) => {
return <components.Details entity={item.entity} key={index}/>;
});
const showDetails = detailItems.find((item) => item.priority > 999) === undefined;
renderContent(entity: T) {
const { onRun, hideDetails } = this.props;
const detailItems = CatalogEntityDetailRegistry.getInstance().getItemsForKind(entity.kind, entity.apiVersion);
const details = detailItems.map(({ components }, index) => <components.Details entity={entity} key={index} />);
const showDefaultDetails = detailItems.find((item) => item.priority > 999) === undefined;
return (
<>
{showDetails && (
{showDefaultDetails && (
<div className="flex">
<div className={styles.entityIcon}>
<Avatar
title={item.name}
colorHash={`${item.name}-${item.source}`}
title={entity.getName()}
colorHash={`${entity.getName()}-${entity.getSource()}`}
size={128}
src={item.entity.spec.icon?.src}
src={entity.spec.icon?.src}
data-testid="detail-panel-hot-bar-icon"
background={item.entity.spec.icon?.background}
onClick={() => item.onRun()}
background={entity.spec.icon?.background}
onClick={onRun}
className={styles.avatar}
>
{item.entity.spec.icon?.material && <Icon material={item.entity.spec.icon?.material}/>}
{entity.spec.icon?.material && <Icon material={entity.spec.icon?.material}/>}
</Avatar>
{item?.enabled && (
{entity.isEnabled() && (
<div className={styles.hint}>
Click to open
</div>
@ -80,23 +79,23 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Pro
</div>
<div className={cssNames("box grow", styles.metadata)}>
<DrawerItem name="Name">
{item.name}
{entity.getName()}
</DrawerItem>
<DrawerItem name="Kind">
{item.kind}
{entity.kind}
</DrawerItem>
<DrawerItem name="Source">
{item.source}
{entity.getSource()}
</DrawerItem>
<DrawerItem name="Status">
{item.phase}
{entity.status.phase}
</DrawerItem>
<DrawerItem name="Labels">
{...item.getLabelBadges(this.props.hideDetails)}
{getLabelBadges(entity, hideDetails)}
</DrawerItem>
{isDevelopment && (
<DrawerItem name="Id">
{item.getId()}
{entity.getId()}
</DrawerItem>
)}
</div>
@ -110,19 +109,18 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Pro
}
render() {
const { item, hideDetails } = this.props;
const title = `${item.kind}: ${item.name}`;
const { entity, hideDetails } = this.props;
return (
<Drawer
className={styles.entityDetails}
usePortal={true}
open={true}
title={title}
toolbar={<CatalogEntityDrawerMenu item={item} key={item.getId()} />}
title={`${entity.kind}: ${entity.getName()}`}
toolbar={<CatalogEntityDrawerMenu entity={entity} key={entity.getId()} />}
onClose={hideDetails}
>
{item && this.renderContent(item)}
{this.renderContent(entity)}
</Drawer>
);
}

View File

@ -29,11 +29,10 @@ import { navigate } from "../../navigation";
import { MenuItem } from "../menu";
import { ConfirmDialog } from "../confirm-dialog";
import { Icon } from "../icon";
import type { CatalogEntityItem } from "./catalog-entity-item";
import { HotbarToggleMenuItem } from "./hotbar-toggle-menu-item";
export interface CatalogEntityDrawerMenuProps<T extends CatalogEntity> extends MenuActionsProps {
item: CatalogEntityItem<T> | null | undefined;
entity: T;
}
@observer
@ -50,7 +49,7 @@ export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Comp
menuItems: [],
navigate: (url: string) => navigate(url),
};
this.props.item?.onContextMenuOpen(this.contextMenu);
this.props.entity?.onContextMenuOpen(this.contextMenu);
}
onMenuItemClick(menuItem: CatalogEntityContextMenu) {
@ -108,9 +107,9 @@ export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Comp
}
render() {
const { className, item: entity, ...menuProps } = this.props;
const { className, entity, ...menuProps } = this.props;
if (!this.contextMenu || !entity.enabled) {
if (!this.contextMenu || !entity.isEnabled()) {
return null;
}
@ -120,7 +119,7 @@ export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Comp
toolbar
{...menuProps}
>
{this.getMenuItems(entity.entity)}
{this.getMenuItems(entity)}
</MenuActions>
);
}

View File

@ -25,9 +25,8 @@ import type { CatalogEntity } from "../../api/catalog-entity";
import { ItemStore } from "../../../common/item.store";
import { CatalogCategory, catalogCategoryRegistry } from "../../../common/catalog";
import { autoBind, disposer } from "../../../common/utils";
import { CatalogEntityItem } from "./catalog-entity-item";
export class CatalogEntityStore extends ItemStore<CatalogEntityItem<CatalogEntity>> {
export class CatalogEntityStore extends ItemStore<CatalogEntity> {
constructor(private registry: CatalogEntityRegistry = catalogEntityRegistry) {
super();
makeObservable(this);
@ -39,10 +38,10 @@ export class CatalogEntityStore extends ItemStore<CatalogEntityItem<CatalogEntit
@computed get entities() {
if (!this.activeCategory) {
return this.registry.filteredItems.map(entity => new CatalogEntityItem(entity, this.registry));
return this.registry.filteredItems;
}
return this.registry.getItemsForCategory(this.activeCategory, { filtered: true }).map(entity => new CatalogEntityItem(entity, this.registry));
return this.registry.getItemsForCategory(this.activeCategory, { filtered: true });
}
@computed get selectedItem() {
@ -68,4 +67,8 @@ export class CatalogEntityStore extends ItemStore<CatalogEntityItem<CatalogEntit
// concurrency is true to fix bug if catalog filter is removed and added at the same time
return this.loadItems(() => this.entities, undefined, true);
}
onRun(entity: CatalogEntity): void {
this.registry.onRun(entity);
}
}

View File

@ -29,7 +29,6 @@ import { kubernetesClusterCategory } from "../../../common/catalog-entities/kube
import { catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntity, CatalogEntityActionContext, CatalogEntityData } from "../../../common/catalog";
import { CatalogEntityRegistry } from "../../../renderer/api/catalog-entity-registry";
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
import { CatalogEntityItem } from "./catalog-entity-item";
import { CatalogEntityStore } from "./catalog-entity.store";
import { AppPaths } from "../../../common/app-paths";
@ -130,7 +129,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);
const catalogEntityItem = createMockCatalogEntity(onRun);
// mock as if there is a selected item > the detail panel opens
jest
@ -166,7 +165,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);
const catalogEntityItem = createMockCatalogEntity(onRun);
// mock as if there is a selected item > the detail panel opens
jest
@ -200,7 +199,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);
const catalogEntityItem = createMockCatalogEntity(onRun);
// mock as if there is a selected item > the detail panel opens
jest
@ -235,7 +234,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn(() => done());
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);
const catalogEntityItem = createMockCatalogEntity(onRun);
// mock as if there is a selected item > the detail panel opens
jest
@ -265,7 +264,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);
const catalogEntityItem = createMockCatalogEntity(onRun);
// mock as if there is a selected item > the detail panel opens
jest
@ -302,7 +301,7 @@ describe("<Catalog />", () => {
const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry);
const onRun = jest.fn();
const catalogEntityItem = new CatalogEntityItem(createMockCatalogEntity(onRun), catalogEntityRegistry);
const catalogEntityItem = createMockCatalogEntity(onRun);
// mock as if there is a selected item > the detail panel opens
jest

View File

@ -26,7 +26,6 @@ import { disposeOnUnmount, observer } from "mobx-react";
import { ItemListLayout } from "../item-object-list";
import { action, makeObservable, observable, reaction, runInAction, when } from "mobx";
import { CatalogEntityStore } from "./catalog-entity.store";
import type { CatalogEntityItem } from "./catalog-entity-item";
import { navigate } from "../../navigation";
import { MenuItem, MenuActions } from "../menu";
import type { CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../api/catalog-entity";
@ -45,6 +44,8 @@ import { RenderDelay } from "../render-delay/render-delay";
import { Icon } from "../icon";
import { HotbarToggleMenuItem } from "./hotbar-toggle-menu-item";
import { Avatar } from "../avatar";
import { KubeObject } from "../../../common/k8s-api/kube-object";
import { getLabelBadges } from "./helpers";
export const previousActiveTab = createStorage("catalog-previous-active-tab", browseCatalogTab);
@ -125,19 +126,19 @@ export class Catalog extends React.Component<Props> {
}));
}
addToHotbar(item: CatalogEntityItem<CatalogEntity>): void {
HotbarStore.getInstance().addToHotbar(item.entity);
addToHotbar(entity: CatalogEntity): void {
HotbarStore.getInstance().addToHotbar(entity);
}
removeFromHotbar(item: CatalogEntityItem<CatalogEntity>): void {
HotbarStore.getInstance().removeFromHotbar(item.getId());
removeFromHotbar(entity: CatalogEntity): void {
HotbarStore.getInstance().removeFromHotbar(entity.getId());
}
onDetails = (item: CatalogEntityItem<CatalogEntity>) => {
onDetails = (entity: CatalogEntity) => {
if (this.catalogEntityStore.selectedItemId) {
this.catalogEntityStore.selectedItemId = null;
} else {
item.onRun();
this.catalogEntityStore.onRun(entity);
}
};
@ -179,16 +180,16 @@ export class Catalog extends React.Component<Props> {
);
}
renderItemMenu = (item: CatalogEntityItem<CatalogEntity>) => {
renderItemMenu = (entity: CatalogEntity) => {
const onOpen = () => {
this.contextMenu.menuItems = [];
item.onContextMenuOpen(this.contextMenu);
entity.onContextMenuOpen(this.contextMenu);
};
return (
<MenuActions onOpen={onOpen}>
<MenuItem key="open-details" onClick={() => this.catalogEntityStore.selectedItemId = item.getId()}>
<MenuItem key="open-details" onClick={() => this.catalogEntityStore.selectedItemId = entity.getId()}>
View Details
</MenuItem>
{
@ -200,7 +201,7 @@ export class Catalog extends React.Component<Props> {
}
<HotbarToggleMenuItem
key="hotbar-toggle"
entity={item.entity}
entity={entity}
addContent="Add to Hotbar"
removeContent="Remove from Hotbar"
/>
@ -208,29 +209,29 @@ export class Catalog extends React.Component<Props> {
);
};
renderName(item: CatalogEntityItem<CatalogEntity>) {
const isItemInHotbar = HotbarStore.getInstance().isAddedToActive(item.entity);
renderName(entity: CatalogEntity) {
const isItemInHotbar = HotbarStore.getInstance().isAddedToActive(entity);
return (
<>
<Avatar
title={item.getName()}
colorHash={`${item.getName()}-${item.source}`}
src={item.entity.spec.icon?.src}
background={item.entity.spec.icon?.background}
title={entity.getName()}
colorHash={`${entity.getName()}-${entity.getSource()}`}
src={entity.spec.icon?.src}
background={entity.spec.icon?.background}
className={styles.catalogAvatar}
size={24}
>
{item.entity.spec.icon?.material && <Icon material={item.entity.spec.icon?.material} small/>}
{entity.spec.icon?.material && <Icon material={entity.spec.icon?.material} small/>}
</Avatar>
<span>{item.name}</span>
<span>{entity.getName()}</span>
<Icon
small
className={styles.pinIcon}
material={!isItemInHotbar && "push_pin"}
svg={isItemInHotbar ? "push_off" : "push_pin"}
tooltip={isItemInHotbar ? "Remove from Hotbar" : "Add to Hotbar"}
onClick={prevDefault(() => isItemInHotbar ? this.removeFromHotbar(item) : this.addToHotbar(item))}
onClick={prevDefault(() => isItemInHotbar ? this.removeFromHotbar(entity) : this.addToHotbar(entity))}
/>
</>
);
@ -253,13 +254,19 @@ export class Catalog extends React.Component<Props> {
isConfigurable={true}
store={this.catalogEntityStore}
sortingCallbacks={{
[sortBy.name]: item => item.name,
[sortBy.source]: item => item.source,
[sortBy.status]: item => item.phase,
[sortBy.kind]: item => item.kind,
[sortBy.name]: entity => entity.getName(),
[sortBy.source]: entity => entity.getSource(),
[sortBy.status]: entity => entity.status.phase,
[sortBy.kind]: entity => entity.kind,
}}
searchFilters={[
entity => entity.searchFields,
entity => [
entity.getName(),
entity.getId(),
entity.status.phase,
`source=${entity.getSource()}`,
...KubeObject.stringifyLabels(entity.metadata.labels),
],
]}
renderTableHeader={[
{ title: "Name", className: styles.entityName, sortBy: sortBy.name, id: "name" },
@ -268,15 +275,15 @@ export class Catalog extends React.Component<Props> {
{ title: "Labels", className: `${styles.labelsCell} scrollable`, id: "labels" },
{ title: "Status", className: styles.statusCell, sortBy: sortBy.status, id: "status" },
].filter(Boolean)}
customizeTableRowProps={item => ({
disabled: !item.enabled,
customizeTableRowProps={entity => ({
disabled: !entity.isEnabled(),
})}
renderTableContents={item => [
this.renderName(item),
!activeCategory && item.kind,
item.source,
item.getLabelBadges(),
<span key="phase" className={item.phase}>{item.phase}</span>,
renderTableContents={entity => [
this.renderName(entity),
!activeCategory && entity.kind,
entity.getSource(),
getLabelBadges(entity),
<span key="phase" className={entity.status.phase}>{entity.status.phase}</span>,
].filter(Boolean)}
onDetails={this.onDetails}
renderItemMenu={this.renderItemMenu}
@ -289,16 +296,19 @@ export class Catalog extends React.Component<Props> {
return null;
}
const selectedEntity = this.catalogEntityStore.selectedItem;
return (
<MainLayout sidebar={this.renderNavigation()}>
<div className="p-6 h-full">
{this.renderList()}
</div>
{
this.catalogEntityStore.selectedItem
selectedEntity
? <CatalogEntityDetails
item={this.catalogEntityStore.selectedItem}
entity={selectedEntity}
hideDetails={() => this.catalogEntityStore.selectedItemId = null}
onRun={() => this.catalogEntityStore.onRun(selectedEntity)}
/>
: (
<RenderDelay>

View File

@ -0,0 +1,49 @@
/**
* 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.scss";
import React from "react";
import { KubeObject } from "../../../common/k8s-api/kube-object";
import type { CatalogEntity } from "../../api/catalog-entity";
import { Badge } from "../badge";
import { searchUrlParam } from "../input";
/**
* @param entity The entity to render badge labels for
*/
export function getLabelBadges(entity: CatalogEntity, onClick?: (evt: React.MouseEvent<any, MouseEvent>) => void) {
return KubeObject.stringifyLabels(entity.metadata.labels)
.map(label => (
<Badge
scrollable
className={styles.badge}
key={label}
label={label}
title={label}
onClick={(event) => {
searchUrlParam.set(label);
onClick?.(event);
event.stopPropagation();
}}
expandable={false}
/>
));
}