// SPDX-License-Identifier: AGPL-3.0-or-later import * as Modal from '@app/features/app/components/dialogs/Modal'; import styles from '@app/features/devtools/components/debug/DebugModal.module.css'; import {CodeBlockRenderer} from '@app/features/messaging/components/markdown/renderers/common/CodeElements'; import {MarkdownContext} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; import {NodeType} from '@app/features/messaging/utils/markdown/parser/Enums'; import type {CodeBlockNode} from '@app/features/messaging/utils/markdown/parser/Nodes'; import {Logger} from '@app/features/platform/utils/AppLogger'; import markupStyles from '@app/features/theme/styles/Markup.module.css'; import {type TabItem, Tabs} from '@app/features/ui/tabs/Tabs'; import {Trans, useLingui} from '@lingui/react/macro'; import {clsx} from 'clsx'; import {observer} from 'mobx-react-lite'; import type React from 'react'; import {useMemo, useState} from 'react'; export interface DebugTab { id: string; label: string; data: unknown; summary?: React.ReactNode; language?: string; serialize?: (value: unknown) => string; } interface DebugModalProps { title: string; tabs: Array; defaultTab?: string; } const logger = new Logger('DebugModal'); export const DebugModal: React.FC = observer(({title, tabs, defaultTab}) => { const {i18n} = useLingui(); const [activeTabId, setActiveTabId] = useState(defaultTab ?? tabs[0]?.id ?? ''); const activeTab = useMemo(() => tabs.find((tab) => tab.id === activeTabId) ?? tabs[0], [tabs, activeTabId]); const tabItems = useMemo>>(() => tabs.map(({id, label}) => ({key: id, label})), [tabs]); const codeContent = useMemo(() => { if (!activeTab) return 'No data available'; if (activeTab.serialize) { try { return activeTab.serialize(activeTab.data); } catch (error) { logger.error('Failed to serialize debug tab data via custom serializer:', error); return 'Unable to serialize data'; } } if (activeTab.data == null) { return 'No data available'; } if (typeof activeTab.data === 'string') { return activeTab.data; } try { return JSON.stringify(activeTab.data, null, 2); } catch (error) { logger.error('Failed to stringify debug tab data:', error); return 'Unable to serialize data'; } }, [activeTab]); const codeNode = useMemo( () => ({ type: NodeType.CodeBlock, content: codeContent, language: activeTab?.language ?? 'json', }), [codeContent, activeTab?.language], ); return (
{tabs.length > 1 && (
setActiveTabId(tabKey)} className={styles.tabs} data-flx="devtools.debug.debug-modal.tabs" />
)}
{activeTab?.summary && (

Summary

{activeTab.summary}
)}
null} options={{ context: MarkdownContext.STANDARD_WITHOUT_JUMBO, shouldJumboEmojis: false, i18n, }} data-flx="devtools.debug.debug-modal.code-block-renderer" />
); }); interface SummaryItemProps { label: string; value: React.ReactNode; } export const SummaryItem: React.FC = observer(({label, value}) => (
{label} {value}
));