mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fix circular dependency on catalogCategoryRegistry
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
56a42ea9ff
commit
fb154f0674
@ -22,18 +22,6 @@ export class GeneralEntity extends CatalogEntity<CatalogEntityMetadata, CatalogE
|
||||
async onRun() {
|
||||
navigate(this.spec.path);
|
||||
}
|
||||
|
||||
public onSettingsOpen(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public onDetailsOpen(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public onContextMenuOpen(): void {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export class GeneralCategory extends CatalogCategory {
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
|
||||
import type { CatalogEntityActionContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus, CatalogCategorySpec } from "../catalog";
|
||||
import { CatalogEntity, CatalogCategory, categoryVersion } from "../catalog/catalog-entity";
|
||||
import { ClusterStore } from "../cluster-store/cluster-store";
|
||||
@ -103,7 +102,7 @@ export class KubernetesCluster<
|
||||
//
|
||||
}
|
||||
|
||||
async onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
||||
onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
||||
if (!this.metadata.source || this.metadata.source === "local") {
|
||||
context.menuItems.push({
|
||||
title: "Settings",
|
||||
@ -132,10 +131,6 @@ export class KubernetesCluster<
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
catalogCategoryRegistry
|
||||
.getCategoryForEntity<KubernetesClusterCategory>(this)
|
||||
?.emit("contextMenuOpen", this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
|
||||
import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity";
|
||||
import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
|
||||
import { productName } from "../vars";
|
||||
import { WeblinkStore } from "../weblink-store";
|
||||
|
||||
@ -30,11 +29,7 @@ export class WebLink extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus,
|
||||
window.open(this.spec.url, "_blank");
|
||||
}
|
||||
|
||||
public onSettingsOpen(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
async onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
||||
onContextMenuOpen(context: CatalogEntityContextMenuContext) {
|
||||
if (this.metadata.source === "local") {
|
||||
context.menuItems.push({
|
||||
title: "Delete",
|
||||
@ -45,10 +40,6 @@ export class WebLink extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
catalogCategoryRegistry
|
||||
.getCategoryForEntity(this)
|
||||
?.emit("contextMenuOpen", this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -396,7 +396,7 @@ export abstract class CatalogEntity<
|
||||
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>;
|
||||
public onRun?(context: CatalogEntityActionContext): void | Promise<void>;
|
||||
public onContextMenuOpen?(context: CatalogEntityContextMenuContext): void | Promise<void>;
|
||||
public onSettingsOpen?(context: CatalogEntitySettingsContext): void | Promise<void>;
|
||||
}
|
||||
|
||||
23
src/common/catalog/on-context-menu-open.injectable.ts
Normal file
23
src/common/catalog/on-context-menu-open.injectable.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { CatalogEntity, CatalogEntityContextMenuContext } from "./catalog-entity";
|
||||
import catalogCategoryRegistryInjectable from "./category-registry.injectable";
|
||||
|
||||
export type OnContextMenuOpen = (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void;
|
||||
|
||||
const onContextMenuOpenInjectable = getInjectable({
|
||||
id: "on-context-menu-open",
|
||||
instantiate: (di): OnContextMenuOpen => {
|
||||
const categoryRegistry = di.inject(catalogCategoryRegistryInjectable);
|
||||
|
||||
return (entity, context) => {
|
||||
entity.onContextMenuOpen?.(context);
|
||||
categoryRegistry.getCategoryForEntity(entity)?.emit("contextMenuOpen", entity, context);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default onContextMenuOpenInjectable;
|
||||
@ -15,17 +15,24 @@ import { MenuItem } from "../menu";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { Icon } from "../icon";
|
||||
import { HotbarToggleMenuItem } from "./hotbar-toggle-menu-item";
|
||||
import type { OnContextMenuOpen } from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import onContextMenuOpenInjectable from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
|
||||
export interface CatalogEntityDrawerMenuProps<T extends CatalogEntity> extends MenuActionsProps {
|
||||
entity: T;
|
||||
export interface CatalogEntityDrawerMenuProps<Entity extends CatalogEntity> extends MenuActionsProps {
|
||||
entity: Entity;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
onContextMenuOpen: OnContextMenuOpen;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Component<CatalogEntityDrawerMenuProps<T>> {
|
||||
class NonInjectedCatalogEntityDrawerMenu<Entity extends CatalogEntity> extends React.Component<Dependencies & CatalogEntityDrawerMenuProps<Entity>> {
|
||||
private readonly menuItems = observable.array<CatalogEntityContextMenu>();
|
||||
|
||||
componentDidMount() {
|
||||
this.props.entity?.onContextMenuOpen({
|
||||
this.props.onContextMenuOpen(this.props.entity, {
|
||||
menuItems: this.menuItems,
|
||||
navigate: (url) => navigate(url),
|
||||
});
|
||||
@ -48,7 +55,7 @@ export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Comp
|
||||
}
|
||||
}
|
||||
|
||||
getMenuItems(entity: T): React.ReactChild[] {
|
||||
getMenuItems(entity: Entity): React.ReactChild[] {
|
||||
if (!entity) {
|
||||
return [];
|
||||
}
|
||||
@ -117,3 +124,10 @@ export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Comp
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const CatalogEntityDrawerMenu = withInjectables<Dependencies, CatalogEntityDrawerMenuProps<CatalogEntity>>(NonInjectedCatalogEntityDrawerMenu, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
onContextMenuOpen: di.inject(onContextMenuOpenInjectable),
|
||||
}),
|
||||
}) as <Entity extends CatalogEntity>(props: CatalogEntityDrawerMenuProps<Entity>) => JSX.Element;
|
||||
|
||||
@ -15,8 +15,7 @@ import { navigate } from "../../navigation";
|
||||
import { MenuItem, MenuActions } from "../menu";
|
||||
import type { CatalogEntityContextMenu } from "../../api/catalog-entity";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import type { CatalogCategory, CatalogEntity } from "../../../common/catalog";
|
||||
import { catalogCategoryRegistry } from "../../../common/catalog";
|
||||
import type { CatalogCategory, CatalogCategoryRegistry, CatalogEntity } from "../../../common/catalog";
|
||||
import { CatalogAddButton } from "./catalog-add-button";
|
||||
import { Notifications } from "../notifications";
|
||||
import { MainLayout } from "../layout/main-layout";
|
||||
@ -43,6 +42,9 @@ import type { AppEvent } from "../../../common/app-event-bus/event-bus";
|
||||
import appEventBusInjectable from "../../../common/app-event-bus/app-event-bus.injectable";
|
||||
import hotbarStoreInjectable from "../../../common/hotbars/store.injectable";
|
||||
import type { HotbarStore } from "../../../common/hotbars/store";
|
||||
import type { OnContextMenuOpen } from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
||||
import onContextMenuOpenInjectable from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
catalogPreviousActiveTabStorage: { set: (value: string ) => void; get: () => string };
|
||||
@ -50,14 +52,14 @@ interface Dependencies {
|
||||
getCategoryColumns: (params: GetCategoryColumnsParams) => CategoryColumns;
|
||||
customCategoryViews: IComputedValue<Map<string, Map<string, RegisteredCustomCategoryViewDecl>>>;
|
||||
emitEvent: (event: AppEvent) => void;
|
||||
|
||||
routeParameters: {
|
||||
group: IComputedValue<string>;
|
||||
kind: IComputedValue<string>;
|
||||
};
|
||||
|
||||
navigateToCatalog: NavigateToCatalog;
|
||||
hotbarStore: HotbarStore;
|
||||
catalogCategoryRegistry: CatalogCategoryRegistry;
|
||||
onContextMenuOpen: OnContextMenuOpen;
|
||||
}
|
||||
|
||||
@observer
|
||||
@ -91,16 +93,24 @@ class NonInjectedCatalog extends React.Component<Dependencies> {
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const {
|
||||
catalogEntityStore,
|
||||
catalogPreviousActiveTabStorage,
|
||||
catalogCategoryRegistry,
|
||||
} = this.props;
|
||||
|
||||
disposeOnUnmount(this, [
|
||||
this.props.catalogEntityStore.watch(),
|
||||
catalogEntityStore.watch(),
|
||||
reaction(() => this.routeActiveTab, async (routeTab) => {
|
||||
catalogPreviousActiveTabStorage.set(this.routeActiveTab);
|
||||
|
||||
try {
|
||||
await when(() => (routeTab === browseCatalogTab || !!catalogCategoryRegistry.filteredItems.find(i => i.getId() === routeTab)), { timeout: 5_000 }); // we need to wait because extensions might take a while to load
|
||||
const item = catalogCategoryRegistry.filteredItems.find(i => i.getId() === routeTab);
|
||||
|
||||
runInAction(() => {
|
||||
this.activeTab = routeTab;
|
||||
this.props.catalogEntityStore.activeCategory.set(item);
|
||||
catalogEntityStore.activeCategory.set(item);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@ -112,22 +122,21 @@ class NonInjectedCatalog extends React.Component<Dependencies> {
|
||||
));
|
||||
}
|
||||
}, { fireImmediately: true }),
|
||||
// If active category is filtered out, automatically switch to the first category
|
||||
reaction(() => catalogCategoryRegistry.filteredItems, () => {
|
||||
if (!catalogCategoryRegistry.filteredItems.find(item => item.getId() === catalogEntityStore.activeCategory.get()?.getId())) {
|
||||
const item = catalogCategoryRegistry.filteredItems[0];
|
||||
|
||||
runInAction(() => {
|
||||
if (item) {
|
||||
this.activeTab = item.getId();
|
||||
this.props.catalogEntityStore.activeCategory.set(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}),
|
||||
]);
|
||||
|
||||
// If active category is filtered out, automatically switch to the first category
|
||||
disposeOnUnmount(this, reaction(() => catalogCategoryRegistry.filteredItems, () => {
|
||||
if (!catalogCategoryRegistry.filteredItems.find(item => item.getId() === this.props.catalogEntityStore.activeCategory.get()?.getId())) {
|
||||
const item = catalogCategoryRegistry.filteredItems[0];
|
||||
|
||||
runInAction(() => {
|
||||
if (item) {
|
||||
this.activeTab = item.getId();
|
||||
this.props.catalogEntityStore.activeCategory.set(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
this.props.emitEvent({
|
||||
name: "catalog",
|
||||
action: "open",
|
||||
@ -168,7 +177,7 @@ class NonInjectedCatalog extends React.Component<Dependencies> {
|
||||
}
|
||||
|
||||
get categories() {
|
||||
return catalogCategoryRegistry.items;
|
||||
return this.props.catalogCategoryRegistry.items;
|
||||
}
|
||||
|
||||
onTabChange = action((tabId: string | null) => {
|
||||
@ -194,7 +203,7 @@ class NonInjectedCatalog extends React.Component<Dependencies> {
|
||||
renderItemMenu = (entity: CatalogEntity) => {
|
||||
const onOpen = () => {
|
||||
this.menuItems.clear();
|
||||
entity.onContextMenuOpen({
|
||||
this.props.onContextMenuOpen(entity, {
|
||||
menuItems: this.menuItems,
|
||||
navigate: (url) => navigate(url),
|
||||
});
|
||||
@ -358,5 +367,7 @@ export const Catalog = withInjectables<Dependencies>( NonInjectedCatalog, {
|
||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||
emitEvent: di.inject(appEventBusInjectable).emit,
|
||||
hotbarStore: di.inject(hotbarStoreInjectable),
|
||||
catalogCategoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||
onContextMenuOpen: di.inject(onContextMenuOpenInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -10,15 +10,18 @@ import React from "react";
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
import type { CatalogEntity, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../../common/catalog";
|
||||
import { catalogCategoryRegistry } from "../../api/catalog-category-registry";
|
||||
import type { CatalogCategoryRegistry, CatalogEntity, CatalogEntityContextMenu } from "../../../common/catalog";
|
||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
||||
import { navigate } from "../../navigation";
|
||||
import type { IClassName } from "../../utils";
|
||||
import { cssNames } from "../../utils";
|
||||
import { Icon } from "../icon";
|
||||
import { HotbarIcon } from "./hotbar-icon";
|
||||
import { LensKubernetesClusterStatus } from "../../../common/catalog-entities/kubernetes-cluster";
|
||||
import type { OnContextMenuOpen } from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
import { navigate } from "../../navigation";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
||||
import onContextMenuOpenInjectable from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
|
||||
export interface HotbarEntityIconProps extends HTMLAttributes<HTMLElement> {
|
||||
entity: CatalogEntity;
|
||||
@ -29,21 +32,23 @@ export interface HotbarEntityIconProps extends HTMLAttributes<HTMLElement> {
|
||||
size?: number;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class HotbarEntityIcon extends React.Component<HotbarEntityIconProps> {
|
||||
@observable private contextMenu: CatalogEntityContextMenuContext = {
|
||||
menuItems: [],
|
||||
navigate: (url: string) => navigate(url),
|
||||
};
|
||||
interface Dependencies {
|
||||
onContextMenuOpen: OnContextMenuOpen;
|
||||
catalogCategoryRegistry: CatalogCategoryRegistry;
|
||||
}
|
||||
|
||||
constructor(props: HotbarEntityIconProps) {
|
||||
@observer
|
||||
class NonInjectedHotbarEntityIcon extends React.Component<HotbarEntityIconProps & Dependencies> {
|
||||
private readonly menuItems = observable.array<CatalogEntityContextMenu>();
|
||||
|
||||
constructor(props: HotbarEntityIconProps & Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
get kindIcon() {
|
||||
const className = styles.badge;
|
||||
const category = catalogCategoryRegistry.getCategoryForEntity(this.props.entity);
|
||||
const category = this.props.catalogCategoryRegistry.getCategoryForEntity(this.props.entity);
|
||||
|
||||
if (!category) {
|
||||
return <Icon material="bug_report" className={className} />;
|
||||
@ -70,24 +75,19 @@ export class HotbarEntityIcon extends React.Component<HotbarEntityIconProps> {
|
||||
return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId();
|
||||
}
|
||||
|
||||
async onMenuOpen() {
|
||||
const menuItems: CatalogEntityContextMenu[] = [];
|
||||
|
||||
menuItems.unshift({
|
||||
onMenuOpen() {
|
||||
this.menuItems.replace([{
|
||||
title: "Remove from Hotbar",
|
||||
onClick: () => this.props.remove(this.props.entity.getId()),
|
||||
}]);
|
||||
|
||||
this.props.onContextMenuOpen(this.props.entity, {
|
||||
menuItems: this.menuItems,
|
||||
navigate,
|
||||
});
|
||||
|
||||
this.contextMenu.menuItems = menuItems;
|
||||
|
||||
await this.props.entity.onContextMenuOpen(this.contextMenu);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.contextMenu) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { entity, errorClass, add, remove, index, children, ...elemProps } = this.props;
|
||||
|
||||
return (
|
||||
@ -102,7 +102,7 @@ export class HotbarEntityIcon extends React.Component<HotbarEntityIconProps> {
|
||||
active={this.isActive(entity)}
|
||||
onMenuOpen={() => this.onMenuOpen()}
|
||||
disabled={!entity}
|
||||
menuItems={this.contextMenu.menuItems}
|
||||
menuItems={this.menuItems}
|
||||
tooltip={(
|
||||
entity.metadata.source
|
||||
? `${entity.getName()} (${entity.metadata.source})`
|
||||
@ -116,3 +116,11 @@ export class HotbarEntityIcon extends React.Component<HotbarEntityIconProps> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const HotbarEntityIcon = withInjectables<Dependencies, HotbarEntityIconProps>(NonInjectedHotbarEntityIcon, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
catalogCategoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||
onContextMenuOpen: di.inject(onContextMenuOpenInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -19,6 +19,8 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import hotbarStoreInjectable from "../../../common/hotbars/store.injectable";
|
||||
import type { HotbarStore } from "../../../common/hotbars/store";
|
||||
import { observer } from "mobx-react";
|
||||
import type { OnContextMenuOpen } from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
import onContextMenuOpenInjectable from "../../../common/catalog/on-context-menu-open.injectable";
|
||||
|
||||
const contextMenu: CatalogEntityContextMenuContext = observable({
|
||||
menuItems: [],
|
||||
@ -64,13 +66,18 @@ function renderLoadingSidebarCluster() {
|
||||
|
||||
interface Dependencies {
|
||||
hotbarStore: HotbarStore;
|
||||
onContextMenuOpen: OnContextMenuOpen;
|
||||
}
|
||||
|
||||
interface SidebarClusterProps {
|
||||
clusterEntity: CatalogEntity | undefined;
|
||||
}
|
||||
|
||||
const NonInjectedSidebarCluster = observer(({ clusterEntity, hotbarStore }: Dependencies & SidebarClusterProps) => {
|
||||
const NonInjectedSidebarCluster = observer(({
|
||||
clusterEntity,
|
||||
hotbarStore,
|
||||
onContextMenuOpen,
|
||||
}: Dependencies & SidebarClusterProps) => {
|
||||
const [opened, setOpened] = useState(false);
|
||||
|
||||
if (!clusterEntity) {
|
||||
@ -87,7 +94,7 @@ const NonInjectedSidebarCluster = observer(({ clusterEntity, hotbarStore }: Depe
|
||||
: () => hotbarStore.addToHotbar(clusterEntity);
|
||||
|
||||
contextMenu.menuItems = [{ title, onClick }];
|
||||
clusterEntity.onContextMenuOpen(contextMenu);
|
||||
onContextMenuOpen(clusterEntity, contextMenu);
|
||||
|
||||
toggle();
|
||||
};
|
||||
@ -150,13 +157,10 @@ const NonInjectedSidebarCluster = observer(({ clusterEntity, hotbarStore }: Depe
|
||||
);
|
||||
});
|
||||
|
||||
export const SidebarCluster = withInjectables<Dependencies, SidebarClusterProps>(
|
||||
NonInjectedSidebarCluster,
|
||||
|
||||
{
|
||||
getProps: (di, props) => ({
|
||||
hotbarStore: di.inject(hotbarStoreInjectable),
|
||||
...props,
|
||||
}),
|
||||
},
|
||||
);
|
||||
export const SidebarCluster = withInjectables<Dependencies, SidebarClusterProps>(NonInjectedSidebarCluster, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
hotbarStore: di.inject(hotbarStoreInjectable),
|
||||
onContextMenuOpen: di.inject(onContextMenuOpenInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -6,10 +6,11 @@
|
||||
import React from "react";
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import type { SingleOrMany } from "../../utils";
|
||||
|
||||
export interface RenderDelayProps {
|
||||
placeholder?: React.ReactNode;
|
||||
children: unknown;
|
||||
children: SingleOrMany<React.ReactNode>;
|
||||
}
|
||||
|
||||
@observer
|
||||
|
||||
Loading…
Reference in New Issue
Block a user