mirror of
https://github.com/lensapp/lens.git
synced 2024-09-20 13:57:23 +03:00
catalog details panel (#2939)
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> Co-authored-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
031c57962b
commit
0fb927f96b
@ -64,6 +64,8 @@ export async function waitForMinikubeDashboard(app: Application) {
|
||||
await app.client.setValue(".Input.SearchInput input", "minikube");
|
||||
await app.client.waitUntilTextExists("div.TableCell", "minikube");
|
||||
await app.client.click("div.TableRow");
|
||||
await app.client.waitUntilTextExists("div.drawer-title-text", "KubernetesCluster: minikube");
|
||||
await app.client.click("div.EntityIcon div.HotbarIcon div div.MuiAvatar-root");
|
||||
await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started");
|
||||
await app.client.waitForExist(`iframe[name="minikube"]`);
|
||||
await app.client.frame("minikube");
|
||||
|
@ -104,6 +104,7 @@ export class KubernetesCluster extends CatalogEntity<CatalogEntityMetadata, Kube
|
||||
context.menuItems = [
|
||||
{
|
||||
title: "Settings",
|
||||
icon: "edit",
|
||||
onlyVisibleForSource: "local",
|
||||
onClick: async () => context.navigate(`/entity/${this.metadata.uid}/settings`)
|
||||
},
|
||||
@ -112,6 +113,7 @@ export class KubernetesCluster extends CatalogEntity<CatalogEntityMetadata, Kube
|
||||
if (this.metadata.labels["file"]?.startsWith(ClusterStore.storedKubeConfigFolder)) {
|
||||
context.menuItems.push({
|
||||
title: "Delete",
|
||||
icon: "delete",
|
||||
onlyVisibleForSource: "local",
|
||||
onClick: async () => ClusterStore.getInstance().removeById(this.metadata.uid),
|
||||
confirm: {
|
||||
@ -123,6 +125,7 @@ export class KubernetesCluster extends CatalogEntity<CatalogEntityMetadata, Kube
|
||||
if (this.status.phase == "connected") {
|
||||
context.menuItems.push({
|
||||
title: "Disconnect",
|
||||
icon: "link_off",
|
||||
onClick: async () => {
|
||||
requestMain(clusterDisconnectHandler, this.metadata.uid);
|
||||
}
|
||||
@ -130,6 +133,7 @@ export class KubernetesCluster extends CatalogEntity<CatalogEntityMetadata, Kube
|
||||
} else {
|
||||
context.menuItems.push({
|
||||
title: "Connect",
|
||||
icon: "link",
|
||||
onClick: async () => {
|
||||
context.navigate(`/cluster/${this.metadata.uid}`);
|
||||
}
|
||||
@ -147,7 +151,7 @@ export class KubernetesClusterCategory extends CatalogCategory {
|
||||
public readonly kind = "CatalogCategory";
|
||||
public metadata = {
|
||||
name: "Kubernetes Clusters",
|
||||
icon: require(`!!raw-loader!./icons/kubernetes.svg`).default // eslint-disable-line
|
||||
icon: require(`!!raw-loader!./icons/kubernetes.svg`).default, // eslint-disable-line
|
||||
};
|
||||
public spec: CatalogCategorySpec = {
|
||||
group: "entity.k8slens.dev",
|
||||
|
@ -96,9 +96,25 @@ export interface CatalogEntityActionContext {
|
||||
}
|
||||
|
||||
export interface CatalogEntityContextMenu {
|
||||
/**
|
||||
* Menu title
|
||||
*/
|
||||
title: string;
|
||||
onlyVisibleForSource?: string; // show only if empty or if matches with entity source
|
||||
/**
|
||||
* Menu icon
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* Show only if empty or if value matches with entity.metadata.source
|
||||
*/
|
||||
onlyVisibleForSource?: string;
|
||||
/**
|
||||
* OnClick handler
|
||||
*/
|
||||
onClick: () => void | Promise<void>;
|
||||
/**
|
||||
* Confirm click with a message
|
||||
*/
|
||||
confirm?: {
|
||||
message: string;
|
||||
}
|
||||
@ -175,7 +191,6 @@ export abstract class CatalogEntity<
|
||||
}
|
||||
|
||||
public abstract onRun?(context: CatalogEntityActionContext): void | Promise<void>;
|
||||
public abstract onDetailsOpen(context: CatalogEntityActionContext): void | Promise<void>;
|
||||
public abstract onContextMenuOpen(context: CatalogEntityContextMenuContext): void | Promise<void>;
|
||||
public abstract onSettingsOpen(context: CatalogEntitySettingsContext): void | Promise<void>;
|
||||
}
|
||||
|
@ -250,6 +250,7 @@ export class ExtensionLoader extends Singleton {
|
||||
registries.statusBarRegistry.add(extension.statusBarItems),
|
||||
registries.commandRegistry.add(extension.commands),
|
||||
registries.welcomeMenuRegistry.add(extension.welcomeMenus),
|
||||
registries.catalogEntityDetailRegistry.add(extension.catalogEntityDetailItems),
|
||||
];
|
||||
|
||||
this.events.on("remove", (removedExtension: LensRendererExtension) => {
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
import type {
|
||||
AppPreferenceRegistration, ClusterPageMenuRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration,
|
||||
AppPreferenceRegistration, CatalogEntityDetailRegistration, ClusterPageMenuRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration,
|
||||
KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, WelcomeMenuRegistration, WorkloadsOverviewDetailRegistration,
|
||||
} from "./registries";
|
||||
import type { Cluster } from "../main/cluster";
|
||||
@ -43,6 +43,7 @@ export class LensRendererExtension extends LensExtension {
|
||||
kubeWorkloadsOverviewItems: WorkloadsOverviewDetailRegistration[] = [];
|
||||
commands: CommandRegistration[] = [];
|
||||
welcomeMenus: WelcomeMenuRegistration[] = [];
|
||||
catalogEntityDetailItems: CatalogEntityDetailRegistration[] = [];
|
||||
|
||||
async navigate<P extends object>(pageId?: string, params?: P) {
|
||||
const { navigate } = await import("../renderer/navigation");
|
||||
|
46
src/extensions/registries/catalog-entity-detail-registry.ts
Normal file
46
src/extensions/registries/catalog-entity-detail-registry.ts
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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 type React from "react";
|
||||
import { BaseRegistry } from "./base-registry";
|
||||
|
||||
export interface CatalogEntityDetailComponents {
|
||||
Details: React.ComponentType<any>;
|
||||
}
|
||||
|
||||
export interface CatalogEntityDetailRegistration {
|
||||
kind: string;
|
||||
apiVersions: string[];
|
||||
components: CatalogEntityDetailComponents;
|
||||
priority?: number;
|
||||
}
|
||||
|
||||
export class CatalogEntityDetailRegistry extends BaseRegistry<CatalogEntityDetailRegistration> {
|
||||
getItemsForKind(kind: string, apiVersion: string) {
|
||||
const items = this.getItems().filter((item) => {
|
||||
return item.kind === kind && item.apiVersions.includes(apiVersion);
|
||||
});
|
||||
|
||||
return items.sort((a, b) => (b.priority ?? 50) - (a.priority ?? 50));
|
||||
}
|
||||
}
|
||||
|
||||
export const catalogEntityDetailRegistry = new CatalogEntityDetailRegistry();
|
@ -33,4 +33,5 @@ export * from "./command-registry";
|
||||
export * from "./entity-setting-registry";
|
||||
export * from "./welcome-menu-registry";
|
||||
export * from "./protocol-handler-registry";
|
||||
export * from "./catalog-entity-detail-registry";
|
||||
export * from "./workloads-overview-detail-registry";
|
||||
|
43
src/renderer/components/+catalog/catalog-entity-details.scss
Normal file
43
src/renderer/components/+catalog/catalog-entity-details.scss
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.CatalogEntityDetails {
|
||||
.EntityMetadata {
|
||||
margin-right: $margin;
|
||||
}
|
||||
.EntityIcon.box.top.left {
|
||||
margin-right: $margin * 2;
|
||||
|
||||
.IconHint {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-small);
|
||||
text-transform: uppercase;
|
||||
margin-top: $margin;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
div * {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
129
src/renderer/components/+catalog/catalog-entity-details.tsx
Normal file
129
src/renderer/components/+catalog/catalog-entity-details.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 "./catalog-entity-details.scss";
|
||||
import React, { Component } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Drawer, DrawerItem, DrawerItemLabels } from "../drawer";
|
||||
import { CatalogEntity, catalogEntityRunContext } from "../../api/catalog-entity";
|
||||
import type { CatalogCategory } from "../../../common/catalog";
|
||||
import { Icon } from "../icon";
|
||||
import { KubeObject } from "../../api/kube-object";
|
||||
import { CatalogEntityDrawerMenu } from "./catalog-entity-drawer-menu";
|
||||
import { catalogEntityDetailRegistry } from "../../../extensions/registries";
|
||||
import { HotbarIcon } from "../hotbar/hotbar-icon";
|
||||
|
||||
interface Props {
|
||||
entity: CatalogEntity;
|
||||
hideDetails(): void;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class CatalogEntityDetails extends Component<Props> {
|
||||
private abortController?: AbortController;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.abortController?.abort();
|
||||
}
|
||||
|
||||
categoryIcon(category: CatalogCategory) {
|
||||
if (category.metadata.icon.includes("<svg")) {
|
||||
return <Icon svg={category.metadata.icon} smallest />;
|
||||
} else {
|
||||
return <Icon material={category.metadata.icon} smallest />;
|
||||
}
|
||||
}
|
||||
|
||||
openEntity() {
|
||||
this.props.entity.onRun(catalogEntityRunContext);
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const { entity } = this.props;
|
||||
const labels = KubeObject.stringifyLabels(entity.metadata.labels);
|
||||
const detailItems = catalogEntityDetailRegistry.getItemsForKind(entity.kind, entity.apiVersion);
|
||||
const details = detailItems.map((item, index) => {
|
||||
return <item.components.Details entity={entity} key={index}/>;
|
||||
});
|
||||
|
||||
const showDetails = detailItems.find((item) => item.priority > 999) === undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
{showDetails && (
|
||||
<div className="flex CatalogEntityDetails">
|
||||
<div className="EntityIcon box top left">
|
||||
<HotbarIcon
|
||||
uid={entity.metadata.uid}
|
||||
title={entity.metadata.name}
|
||||
source={entity.metadata.source}
|
||||
onClick={() => this.openEntity()}
|
||||
size={128} />
|
||||
<div className="IconHint">
|
||||
Click to open
|
||||
</div>
|
||||
</div>
|
||||
<div className="box grow EntityMetadata">
|
||||
<DrawerItem name="Name">
|
||||
{entity.metadata.name}
|
||||
</DrawerItem>
|
||||
<DrawerItem name="Kind">
|
||||
{entity.kind}
|
||||
</DrawerItem>
|
||||
<DrawerItem name="Source">
|
||||
{entity.metadata.source}
|
||||
</DrawerItem>
|
||||
<DrawerItemLabels
|
||||
name="Labels"
|
||||
labels={labels}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="box grow">
|
||||
{details}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { entity, hideDetails } = this.props;
|
||||
const title = `${entity.kind}: ${entity.metadata.name}`;
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
className="CatalogEntityDetails"
|
||||
usePortal={true}
|
||||
open={true}
|
||||
title={title}
|
||||
toolbar={<CatalogEntityDrawerMenu entity={entity} key={entity.getId()} />}
|
||||
onClose={hideDetails}
|
||||
>
|
||||
{this.renderContent()}
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
}
|
127
src/renderer/components/+catalog/catalog-entity-drawer-menu.tsx
Normal file
127
src/renderer/components/+catalog/catalog-entity-drawer-menu.tsx
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* 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 { cssNames } from "../../utils";
|
||||
import { MenuActions, MenuActionsProps } from "../menu/menu-actions";
|
||||
import type { CatalogEntity, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../api/catalog-entity";
|
||||
import { observer } from "mobx-react";
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import { navigate } from "../../navigation";
|
||||
import { MenuItem } from "../menu";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { HotbarStore } from "../../../common/hotbar-store";
|
||||
import { Icon } from "../icon";
|
||||
|
||||
export interface CatalogEntityDrawerMenuProps<T extends CatalogEntity> extends MenuActionsProps {
|
||||
entity: T | null | undefined;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Component<CatalogEntityDrawerMenuProps<T>> {
|
||||
@observable private contextMenu: CatalogEntityContextMenuContext;
|
||||
|
||||
constructor(props: CatalogEntityDrawerMenuProps<T>) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.contextMenu = {
|
||||
menuItems: [],
|
||||
navigate: (url: string) => navigate(url)
|
||||
};
|
||||
this.props.entity?.onContextMenuOpen(this.contextMenu);
|
||||
}
|
||||
|
||||
onMenuItemClick(menuItem: CatalogEntityContextMenu) {
|
||||
if (menuItem.confirm) {
|
||||
ConfirmDialog.open({
|
||||
okButtonProps: {
|
||||
primary: false,
|
||||
accent: true,
|
||||
},
|
||||
ok: () => {
|
||||
menuItem.onClick();
|
||||
},
|
||||
message: menuItem.confirm.message
|
||||
});
|
||||
} else {
|
||||
menuItem.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
addToHotbar(entity: CatalogEntity): void {
|
||||
HotbarStore.getInstance().addToHotbar(entity);
|
||||
}
|
||||
|
||||
getMenuItems(entity: T): React.ReactChild[] {
|
||||
if (!entity) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const menuItems = this.contextMenu.menuItems.filter((menuItem) => {
|
||||
return menuItem.icon && !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === entity.metadata.source;
|
||||
});
|
||||
|
||||
const items = menuItems.map((menuItem, index) => {
|
||||
const props = menuItem.icon.includes("<svg") ? { svg: menuItem.icon } : { material: menuItem.icon };
|
||||
|
||||
return (
|
||||
<MenuItem key={index} onClick={() => this.onMenuItemClick(menuItem)}>
|
||||
<Icon
|
||||
title={menuItem.title}
|
||||
{...props}
|
||||
/>
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
items.unshift(
|
||||
<MenuItem key="add-to-hotbar" onClick={() => this.addToHotbar(entity) }>
|
||||
<Icon material="playlist_add" small title="Add to Hotbar" />
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
items.reverse();
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.contextMenu) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { className, entity, ...menuProps } = this.props;
|
||||
|
||||
return (
|
||||
<MenuActions
|
||||
className={cssNames("CatalogEntityDrawerMenu", className)}
|
||||
toolbar
|
||||
{...menuProps}
|
||||
>
|
||||
{this.getMenuItems(entity)}
|
||||
</MenuActions>
|
||||
);
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ import { navigate } from "../../navigation";
|
||||
import { kebabCase } from "lodash";
|
||||
import { PageLayout } from "../layout/page-layout";
|
||||
import { MenuItem, MenuActions } from "../menu";
|
||||
import { CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity";
|
||||
import type { CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../api/catalog-entity";
|
||||
import { Badge } from "../badge";
|
||||
import { HotbarStore } from "../../../common/hotbar-store";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
@ -40,6 +40,7 @@ import type { RouteComponentProps } from "react-router";
|
||||
import type { ICatalogViewRouteParam } from "./catalog.route";
|
||||
import { Notifications } from "../notifications";
|
||||
import { Avatar } from "../avatar/avatar";
|
||||
import { CatalogEntityDetails } from "./catalog-entity-details";
|
||||
|
||||
enum sortBy {
|
||||
name = "name",
|
||||
@ -55,6 +56,7 @@ export class Catalog extends React.Component<Props> {
|
||||
@observable private catalogEntityStore?: CatalogEntityStore;
|
||||
@observable private contextMenu: CatalogEntityContextMenuContext;
|
||||
@observable activeTab?: string;
|
||||
@observable selectedItem?: CatalogEntityItem;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
@ -103,7 +105,7 @@ export class Catalog extends React.Component<Props> {
|
||||
}
|
||||
|
||||
onDetails(item: CatalogEntityItem) {
|
||||
item.onRun(catalogEntityRunContext);
|
||||
this.selectedItem = item;
|
||||
}
|
||||
|
||||
onMenuItemClick(menuItem: CatalogEntityContextMenu) {
|
||||
@ -181,12 +183,6 @@ export class Catalog extends React.Component<Props> {
|
||||
};
|
||||
|
||||
renderIcon(item: CatalogEntityItem) {
|
||||
const category = catalogCategoryRegistry.getCategoryForEntity(item.entity);
|
||||
|
||||
if (!category) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
title={item.name}
|
||||
@ -269,6 +265,7 @@ export class Catalog extends React.Component<Props> {
|
||||
item.labels.map((label) => <Badge key={label} label={label} title={label} />),
|
||||
{ title: item.phase, className: kebabCase(item.phase) }
|
||||
]}
|
||||
detailsItem={this.selectedItem}
|
||||
onDetails={(item: CatalogEntityItem) => this.onDetails(item) }
|
||||
renderItemMenu={this.renderItemMenu}
|
||||
/>
|
||||
@ -287,7 +284,15 @@ export class Catalog extends React.Component<Props> {
|
||||
provideBackButtonNavigation={false}
|
||||
contentGaps={false}>
|
||||
{ this.catalogEntityStore.activeCategory ? this.renderSingleCategoryList() : this.renderAllCategoriesList() }
|
||||
{ !this.selectedItem && (
|
||||
<CatalogAddButton category={this.catalogEntityStore.activeCategory} />
|
||||
)}
|
||||
{ this.selectedItem && (
|
||||
<CatalogEntityDetails
|
||||
entity={this.selectedItem.entity}
|
||||
hideDetails={() => this.selectedItem = null}
|
||||
/>
|
||||
)}
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ interface Props extends DOMAttributes<HTMLElement> {
|
||||
errorClass?: IClassName;
|
||||
add: (item: CatalogEntity, index: number) => void;
|
||||
remove: (uid: string) => void;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
@observer
|
||||
|
@ -31,7 +31,7 @@ import { MaterialTooltip } from "../material-tooltip/material-tooltip";
|
||||
import { observer } from "mobx-react";
|
||||
import { Avatar } from "../avatar/avatar";
|
||||
|
||||
interface Props extends DOMAttributes<HTMLElement> {
|
||||
export interface HotbarIconProps extends DOMAttributes<HTMLElement> {
|
||||
uid: string;
|
||||
title: string;
|
||||
source: string;
|
||||
@ -40,6 +40,7 @@ interface Props extends DOMAttributes<HTMLElement> {
|
||||
active?: boolean;
|
||||
menuItems?: CatalogEntityContextMenu[];
|
||||
disabled?: boolean;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
function onMenuItemClick(menuItem: CatalogEntityContextMenu) {
|
||||
@ -59,7 +60,7 @@ function onMenuItemClick(menuItem: CatalogEntityContextMenu) {
|
||||
}
|
||||
}
|
||||
|
||||
export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => {
|
||||
export const HotbarIcon = observer(({menuItems = [], size = 40, ...props}: HotbarIconProps) => {
|
||||
const { uid, title, active, className, source, disabled, onMenuOpen, children, ...rest } = props;
|
||||
const id = `hotbarIcon-${uid}`;
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
@ -77,8 +78,8 @@ export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => {
|
||||
title={title}
|
||||
colorHash={`${title}-${source}`}
|
||||
className={active ? "active" : "default"}
|
||||
width={40}
|
||||
height={40}
|
||||
width={size}
|
||||
height={size}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
|
@ -157,6 +157,7 @@ export class HotbarMenu extends React.Component<Props> {
|
||||
className={cssNames({ isDragging: snapshot.isDragging })}
|
||||
remove={this.removeItem}
|
||||
add={this.addItem}
|
||||
size={40}
|
||||
/>
|
||||
) : (
|
||||
<HotbarIcon
|
||||
@ -165,6 +166,7 @@ export class HotbarMenu extends React.Component<Props> {
|
||||
source={item.entity.source}
|
||||
menuItems={disabledMenuItems}
|
||||
disabled
|
||||
size={40}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user