import { ReactElement, useMemo } from 'react'; import { PluginExtensionLink } from '@grafana/data'; import { Menu } from '@grafana/ui'; import { truncateTitle } from 'app/features/plugins/extensions/utils'; type Props = { extensions: PluginExtensionLink[]; onSelect: (extension: PluginExtensionLink) => void; }; export function ToolbarExtensionPointMenu({ extensions, onSelect }: Props): ReactElement | null { const { categorised, uncategorised } = useExtensionLinksByCategory(extensions); const showDivider = uncategorised.length > 0 && Object.keys(categorised).length > 0; return ( <> {Object.keys(categorised).map((category) => ( {renderItems(categorised[category], onSelect)} ))} {showDivider && } {renderItems(uncategorised, onSelect)} ); } function renderItems(extensions: PluginExtensionLink[], onSelect: (link: PluginExtensionLink) => void): JSX.Element[] { return extensions.map((extension) => ( { if (extension.path) { return onSelect(extension); } extension.onClick?.(event); }} /> )); } type ExtensionLinksResult = { uncategorised: PluginExtensionLink[]; categorised: Record; }; function useExtensionLinksByCategory(extensions: PluginExtensionLink[]): ExtensionLinksResult { return useMemo(() => { const uncategorised: PluginExtensionLink[] = []; const categorised: Record = {}; for (const link of extensions) { if (!link.category) { uncategorised.push(link); continue; } if (!Array.isArray(categorised[link.category])) { categorised[link.category] = []; } categorised[link.category].push(link); continue; } return { uncategorised, categorised, }; }, [extensions]); }