Add ability to hide KubeObjectMenu Edit and Remove buttons in extensions (#5107)

This commit is contained in:
Sebastian Malton authored and GitHub committed 2022-05-04 12:44:31 -04:00
1 parent e532b90b72
commit dbdde19222
51 files changed
+1245 -765

No files matched your search

+56 -26
View File
@@ -6,34 +6,47 @@
import "./menu-actions.scss";
import React, { isValidElement } from "react";
import { observable, makeObservable } from "mobx";
import { observer } from "mobx-react";
import { observable, makeObservable, reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { autoBind, cssNames } from "../../utils";
import { ConfirmDialog } from "../confirm-dialog";
import type { IconProps } from "../icon";
import { Icon } from "../icon";
import type { MenuProps } from "./menu";
import { Menu, MenuItem } from "./menu";
import uniqueId from "lodash/uniqueId";
import isString from "lodash/isString";
import type { OpenConfirmDialog } from "../confirm-dialog/open.injectable";
import { withInjectables } from "@ogre-tools/injectable-react";
import openConfirmDialogInjectable from "../confirm-dialog/open.injectable";
export interface MenuActionsProps extends Partial<MenuProps> {
className?: string;
toolbar?: boolean; // display menu as toolbar with icons
autoCloseOnSelect?: boolean;
triggerIcon?: string | IconProps | React.ReactNode;
/**
* @deprecated Provide your own remove `<MenuItem>` as part of the `children` passed to this component
*/
removeConfirmationMessage?: React.ReactNode | (() => React.ReactNode);
updateAction?(): void;
removeAction?(): void;
onOpen?(): void;
/**
* @deprecated Provide your own update `<MenuItem>` as part of the `children` passed to this component
*/
updateAction?: () => void | Promise<void>;
/**
* @deprecated Provide your own remove `<MenuItem>` as part of the `children` passed to this component
*/
removeAction?: () => void | Promise<void>;
onOpen?: () => void;
}
interface Dependencies {
openConfirmDialog: OpenConfirmDialog;
}
@observer
export class MenuActions extends React.Component<MenuActionsProps> {
static defaultProps: MenuActionsProps = {
get removeConfirmationMessage() {
return `Remove item?`;
},
class NonInjectedMenuActions extends React.Component<MenuActionsProps & Dependencies> {
static defaultProps = {
removeConfirmationMessage: "Remove item?",
};
public id = uniqueId("menu_actions_");
@@ -45,22 +58,34 @@ export class MenuActions extends React.Component<MenuActionsProps> {
this.isOpen = !this.isOpen;
};
constructor(props: MenuActionsProps) {
constructor(props: MenuActionsProps & Dependencies) {
super(props);
makeObservable(this);
autoBind(this);
}
componentDidMount(): void {
disposeOnUnmount(this, [
reaction(() => this.isOpen, (isOpen) => {
if (isOpen) {
this.props.onOpen?.();
}
}, {
fireImmediately: true,
}),
]);
}
remove() {
const { removeAction } = this.props;
const { removeAction, openConfirmDialog } = this.props;
let { removeConfirmationMessage } = this.props;
if (typeof removeConfirmationMessage === "function") {
removeConfirmationMessage = removeConfirmationMessage();
}
ConfirmDialog.open({
openConfirmDialog({
ok: removeAction,
labelOk: `Remove`,
labelOk: "Remove",
message: <div>{removeConfirmationMessage}</div>,
});
}
@@ -83,10 +108,6 @@ export class MenuActions extends React.Component<MenuActionsProps> {
...(typeof triggerIcon === "object" ? triggerIcon : {}),
};
if (this.props.onOpen) {
iconProps.onClick = this.props.onOpen;
}
if (iconProps.tooltip && this.isOpen) {
delete iconProps.tooltip; // don't show tooltip for icon when menu is open
}
@@ -101,10 +122,6 @@ export class MenuActions extends React.Component<MenuActionsProps> {
className, toolbar, autoCloseOnSelect, children, updateAction, removeAction, triggerIcon, removeConfirmationMessage,
...menuProps
} = this.props;
const menuClassName = cssNames("MenuActions flex", className, {
toolbar,
gaps: toolbar, // add spacing for .flex
});
const autoClose = !toolbar;
return (
@@ -113,11 +130,17 @@ export class MenuActions extends React.Component<MenuActionsProps> {
<Menu
htmlFor={this.id}
isOpen={this.isOpen} open={this.toggle} close={this.toggle}
className={menuClassName}
isOpen={this.isOpen}
open={this.toggle}
close={this.toggle}
className={cssNames("MenuActions flex", className, {
toolbar,
gaps: toolbar, // add spacing for .flex
})}
animated={!toolbar}
usePortal={autoClose}
closeOnScroll={autoClose}
closeOnClickItem={autoCloseOnSelect ?? autoClose }
closeOnClickItem={autoCloseOnSelect ?? autoClose}
closeOnClickOutside={autoClose}
{...menuProps}
>
@@ -139,3 +162,10 @@ export class MenuActions extends React.Component<MenuActionsProps> {
);
}
}
export const MenuActions = withInjectables<Dependencies, MenuActionsProps>(NonInjectedMenuActions, {
getProps: (di, props) => ({
...props,
openConfirmDialog: di.inject(openConfirmDialogInjectable),
}),
});
+30 -16
View File
@@ -42,6 +42,7 @@ export interface MenuProps {
closeOnScroll?: boolean; // applicable when usePortal={true}
position?: MenuPosition; // applicable when usePortal={false}
children?: ReactNode;
animated?: boolean;
toggleEvent?: "click" | "contextmenu";
}
@@ -58,6 +59,7 @@ const defaultPropsMenu: Partial<MenuProps> = {
closeOnClickOutside: true,
closeOnScroll: false,
toggleEvent: "click",
animated: true,
};
export class Menu extends React.Component<MenuProps, State> {
@@ -297,7 +299,7 @@ export class Menu extends React.Component<MenuProps, State> {
}
render() {
const { position, id } = this.props;
const { position, id, animated } = this.props;
let { className, usePortal } = this.props;
className = cssNames("Menu", className, this.state.position || position, {
@@ -319,28 +321,40 @@ export class Menu extends React.Component<MenuProps, State> {
return item;
});
const menu = (
<MenuContext.Provider value={this}>
let menu = (
<ul
id={id}
ref={this.bindRef}
className={className}
style={{
left: this.state?.menuStyle?.left,
top: this.state?.menuStyle?.top,
}}
onKeyDown={this.onKeyDown}
>
{menuItems}
</ul>
);
if (animated) {
menu = (
<Animate enter={this.isOpen}>
<ul
id={id}
ref={this.bindRef}
className={className}
style={{
left: this.state?.menuStyle?.left,
top: this.state?.menuStyle?.top,
}}
onKeyDown={this.onKeyDown}
>
{menuItems}
</ul>
{menu}
</Animate>
);
}
menu = (
<MenuContext.Provider value={this}>
{menu}
</MenuContext.Provider>
);
if (usePortal === true) usePortal = document.body;
return usePortal instanceof HTMLElement ? createPortal(menu, usePortal) : menu;
return usePortal instanceof HTMLElement
? createPortal(menu, usePortal)
: menu;
}
}