- );
-};
-
-const ActionsMenu_ = ({ actions, impersonate, title = undefined }) => {
- const [isVisible, setVisible] = useSafetyFirst(false);
-
- // Check if any actions are visible when actions have access reviews.
- React.useEffect(() => {
- if (!actions.length) {
- setVisible(false);
- return;
- }
- const promises = actions.reduce((acc, action) => {
- if (action.accessReview) {
- acc.push(checkAccess(action.accessReview));
- }
- return acc;
- }, []);
-
- // Only need to resolve if all actions require access review
- if (promises.length !== actions.length) {
- setVisible(true);
- return;
- }
- Promise.all(promises)
- .then((results) => setVisible(_.some(results, 'status.allowed')))
- .catch(() => setVisible(true));
- }, [actions, impersonate, setVisible]);
- return isVisible ? : null;
-};
-
-export const ActionsMenu = connect(impersonateStateToProps)(ActionsMenu_);
-
-ActionsMenu.propTypes = {
- actions: PropTypes.arrayOf(
- PropTypes.shape({
- label: PropTypes.node,
- labelKey: PropTypes.string,
- href: PropTypes.string,
- callback: PropTypes.func,
- accessReview: PropTypes.object,
- }),
- ).isRequired,
- title: PropTypes.node,
-};
diff --git a/frontend/public/components/utils/headings.tsx b/frontend/public/components/utils/headings.tsx
index 817a6882b98a..ea26f81732c3 100644
--- a/frontend/public/components/utils/headings.tsx
+++ b/frontend/public/components/utils/headings.tsx
@@ -8,9 +8,10 @@ import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { PageHeading, PageHeadingProps } from '@console/shared/src/components/heading/PageHeading';
+import { ActionsMenu } from '@console/internal/components/utils/actions-menu';
import { connectToModel } from '../../kinds';
import { K8sKind, K8sResourceKind, K8sResourceKindReference } from '../../module/k8s';
-import { ActionsMenu, FirehoseResult, KebabOption, ResourceIcon } from './index';
+import { FirehoseResult, KebabOption, ResourceIcon } from './index';
import { ManagedByOperatorLink } from './managed-by';
export const ResourceItemDeleting = () => {
diff --git a/frontend/public/components/utils/index.tsx b/frontend/public/components/utils/index.tsx
index 67a13f9feb98..df5ad59319dd 100644
--- a/frontend/public/components/utils/index.tsx
+++ b/frontend/public/components/utils/index.tsx
@@ -53,7 +53,6 @@ export * from './dom-utils';
export * from './owner-references';
export { default } from './operator-backed-owner-references';
export * from './field-level-help';
-export * from './single-typeahead-dropdown';
export * from './details-item';
export * from './types';
export * from './release-notes-link';
diff --git a/frontend/public/components/utils/kebab.tsx b/frontend/public/components/utils/kebab.tsx
index 8ebd031cf600..ed98874b72ad 100644
--- a/frontend/public/components/utils/kebab.tsx
+++ b/frontend/public/components/utils/kebab.tsx
@@ -1,18 +1,20 @@
-/* eslint-disable @typescript-eslint/no-use-before-define */
import * as _ from 'lodash-es';
import * as React from 'react';
-import classNames from 'classnames';
import { connect } from 'react-redux';
-/* eslint-disable import/named */
import { useTranslation } from 'react-i18next';
import i18next from 'i18next';
-import { KeyTypes, Tooltip, FocusTrap } from '@patternfly/react-core';
-import { AngleRightIcon } from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';
+import {
+ Dropdown,
+ DropdownItem,
+ DropdownList,
+ MenuToggle,
+ MenuToggleElement,
+ Tooltip,
+} from '@patternfly/react-core';
import { EllipsisVIcon } from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
import { useNavigate } from 'react-router-dom-v5-compat';
import { subscribeToExtensions } from '@console/plugin-sdk/src/api/pluginSubscriptionService';
import { KebabActions, isKebabActions } from '@console/plugin-sdk/src/typings/kebab-actions';
-import Popper from '@console/shared/src/components/popper/Popper';
import {
HelmChartRepositoryModel,
ProjectHelmChartRepositoryModel,
@@ -50,9 +52,10 @@ import {
RouteModel,
VolumeSnapshotModel,
} from '../../models';
+import { ContextSubMenuItem } from '@patternfly/react-topology';
export const kebabOptionsToMenu = (options: KebabOption[]): KebabMenuOption[] => {
- const subs: { [key: string]: KebabSubMenu } = {};
+ const subs: { [key: string]: KebabSubMenuOption } = {};
const menuOptions: KebabMenuOption[] = [];
options.forEach((o) => {
@@ -91,37 +94,21 @@ export const kebabOptionsToMenu = (options: KebabOption[]): KebabMenuOption[] =>
const KebabItem_: React.FC = ({
option,
onClick,
- onEscape,
autoFocus,
isAllowed,
}) => {
const { t } = useTranslation();
- const ref = React.useRef(null);
- const disabled = !isAllowed || option.isDisabled || (!option.href && !option.callback);
- React.useEffect(() => {
- const parentNode = ref.current.parentNode; //
- disabled
- ? parentNode.classList.add('pf-m-disabled')
- : parentNode.classList.remove('pf-m-disabled');
- }, [disabled]);
- const handleEscape = (e) => {
- if (e.keyCode === KeyTypes.Escape) {
- onEscape();
- }
- };
+ const isDisabled = !isAllowed || option.isDisabled || (!option.href && !option.callback);
return (
-
+
);
};
export const KebabItemAccessReview_ = (
@@ -134,99 +121,9 @@ export const KebabItemAccessReview_ = (
const KebabItemAccessReview = connect(impersonateStateToProps)(KebabItemAccessReview_);
-type KebabSubMenuProps = {
- option: KebabSubMenu;
- onClick: KebabItemProps['onClick'];
-};
-
-const KebabSubMenu: React.FC = ({ option, onClick }) => {
- const { t } = useTranslation();
- const [open, setOpen] = React.useState(false);
- const nodeRef = React.useRef(null);
- const subMenuRef = React.useRef(null);
- const referenceCb = React.useCallback(() => nodeRef.current, []);
- // use a callback ref because FocusTrap is old and doesn't support non-function refs
- const subMenuCbRef = React.useCallback((node) => (subMenuRef.current = node), []);
-
- return (
- <>
-
- {
- // only close the sub menu if clicking anywhere outside the menu item that owns the sub menu
- if (!e || !nodeRef.current || !nodeRef.current.contains(e.target as Node)) {
- setOpen(false);
- }
- }}
- reference={referenceCb}
- >
- subMenuRef.current, // fallback to popover content wrapper div if there are no tabbable elements
- }}
- >
-
{
- // only close the sub menu if the mouse does not enter the item
- if (!nodeRef.current || !nodeRef.current.contains(e.relatedTarget as Node)) {
- setOpen(false);
- }
- }}
- onKeyDown={(e) => {
- // close the sub menu on left arrow
- if (e.keyCode === 37) {
- setOpen(false);
- e.stopPropagation();
- }
- }}
- >
-
-
-
-
- >
- );
-};
-
-export const isKebabSubMenu = (option: KebabMenuOption): option is KebabSubMenu => {
+export const isKebabSubMenu = (option: KebabMenuOption): option is KebabSubMenuOption => {
// only a sub menu has children
- return Array.isArray((option as KebabSubMenu).children);
+ return Array.isArray((option as KebabSubMenuOption).children);
};
export const KebabItem: React.FC = (props) => {
@@ -256,31 +153,32 @@ type KebabMenuItemsProps = {
className?: string;
};
-export const KebabMenuItems: React.FC = ({
- className,
- options,
- onClick,
- focusItem,
-}) => (
-