// Copyright 2022 The Parca Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import {Icon} from '@iconify/react'; import {Item, Menu, Submenu} from 'react-contexify'; import {useParcaContext} from '@parca/components'; import {TEST_IDS, testId} from '@parca/test-utils'; import {Series, SeriesPoint} from '../'; export interface ContextMenuItem { id: string; label: React.ReactNode; icon?: string; onClick: (closestPoint: SeriesPoint | null, series: Series[]) => void; disabled?: (closestPoint: SeriesPoint | null, series: Series[]) => boolean; } export interface ContextMenuSubmenu { id: string; label: React.ReactNode; icon?: string; items?: ContextMenuItem[]; createDynamicItems?: (closestPoint: SeriesPoint | null, series: Series[]) => ContextMenuItem[]; } export type ContextMenuItemOrSubmenu = ContextMenuItem | ContextMenuSubmenu; interface MetricsContextMenuProps { menuId: string; closestPoint: SeriesPoint | null; series: Series[]; trackVisibility: (isVisible: boolean) => void; menuItems: ContextMenuItemOrSubmenu[]; } const MetricsContextMenu = ({ menuId, closestPoint, series, trackVisibility, menuItems, }: MetricsContextMenuProps): JSX.Element => { const {isDarkMode} = useParcaContext(); const renderMenuItem = (item: ContextMenuItemOrSubmenu): React.ReactNode => { if ('items' in item || 'createDynamicItems' in item) { // This is a submenu const submenu = item; const items = submenu.createDynamicItems != null ? submenu.createDynamicItems(closestPoint, series) : submenu.items ?? []; return ( {submenu.icon != null && submenu.icon !== '' && }
{submenu.label}
} >
{items.map(subItem => ( subItem.onClick(closestPoint, series)} disabled={subItem.disabled?.(closestPoint, series) ?? false} className="max-w-[400px] overflow-hidden" >
{subItem.icon != null && subItem.icon !== '' && }
{subItem.label}
))}
); } else { // This is a regular menu item const menuItem = item as ContextMenuItem; return ( menuItem.onClick(closestPoint, series)} disabled={menuItem.disabled?.(closestPoint, series) ?? false} >
{menuItem.icon != null && menuItem.icon !== '' && }
{menuItem.label}
); } }; return ( {menuItems.map(renderMenuItem)} ); }; export default MetricsContextMenu;