import React, { type ComponentType, Fragment, type ReactElement, useCallback, useMemo } from 'react'; import { type ComponentTypeWithExtensionMeta, type UrlQueryValue } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { Stack, Tab, TabContent, TabsBar } from '@grafana/ui'; import { useQueryParams } from 'app/core/hooks/useQueryParams'; import { t } from 'app/core/internationalization'; const TAB_QUERY_PARAM = 'tab'; const GENERAL_SETTINGS_TAB = 'general'; type Props = { children?: React.ReactNode; components: ComponentTypeWithExtensionMeta[]; }; export function UserProfileEditTabs(props: Props): ReactElement { const { children, components } = props; const tabsById = useTabInfoById(components, children); const [activeTab, setActiveTab] = useActiveTab(tabsById); const showTabs = components.length > 0; if (showTabs === false) { return <>{children}; } return (
{Object.values(tabsById).map(({ tabId, title }) => { return ( setActiveTab(tabId)} data-testid={selectors.components.UserProfile.extensionPointTab(tabId)} /> ); })} {Boolean(activeTab) && ( {activeTab?.components.map((Component, index) => )} )}
); } type TabInfo = { title: string; tabId: string; components: ComponentType[]; }; function useTabInfoById(components: Props['components'], general: React.ReactNode): Record { return useMemo(() => { const tabs: Record = { [GENERAL_SETTINGS_TAB]: { title: t('user-profile.tabs.general', 'General'), tabId: GENERAL_SETTINGS_TAB, components: [() => <>{general}], }, }; return components.reduce((acc, component) => { const { title } = component.meta; const tabId = convertTitleToTabId(title); if (!acc[tabId]) { acc[tabId] = { title, tabId, components: [], }; } acc[tabId].components.push(component); return acc; }, tabs); }, [components, general]); } function useActiveTab(tabs: Record): [TabInfo | undefined, (tabId: string) => void] { const [queryParams, updateQueryParams] = useQueryParams(); const activeTabId = convertQueryParamToTabId(queryParams[TAB_QUERY_PARAM]); const activeTab = tabs[activeTabId]; const setActiveTab = useCallback( (tabId: string) => updateQueryParams({ [TAB_QUERY_PARAM]: tabId }), [updateQueryParams] ); return [activeTab, setActiveTab]; } function convertQueryParamToTabId(queryParam: UrlQueryValue) { if (typeof queryParam !== 'string') { return GENERAL_SETTINGS_TAB; } return convertTitleToTabId(queryParam); } function convertTitleToTabId(title: string) { return title.toLowerCase(); }