/
githubmirror
/
ydb-embedded-ui
Обзор
Документация
Войти
/
githubmirror
/
ydb-embedded-ui
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/containers/Tenant/Query/QueryResult/components/QueryInfoDropdown/useQueryInfoMenuItems.tsx
143 строки
5 KB
Hellen
feat(Header): redesign header for Cluster page (#3813)
28 апр 2026, 16:52
Не верифицирован
28 апр 2026, 16:52
845f0d7
Код
Авторство
О чём код?
import React from 'react'; import {ArrowDownToLine, ArrowUpRightFromSquare} from '@gravity-ui/icons'; import type {DropdownMenuItemWithDescription} from '../../../../../../components/DropdownMenu'; import {planToSvgApi} from '../../../../../../store/reducers/planToSvg'; import type {QueryPlan, ScriptPlan, TKqpStatsQuery} from '../../../../../../types/api/query'; import createToast from '../../../../../../utils/createToast'; import {createAndDownloadJsonFile, downloadFile} from '../../../../../../utils/downloadFile'; import {prepareCommonErrorMessage} from '../../../../../../utils/errors'; import {parseQueryError} from '../../../../../../utils/query'; import i18n from '../../i18n'; export interface QueryResultsInfo { ast?: string; stats?: TKqpStatsQuery; queryText?: string; plan?: QueryPlan | ScriptPlan; } export interface DiagnosticsData extends QueryResultsInfo { database: string; error?: ReturnType<typeof parseQueryError>; } export interface UseQueryInfoMenuItemsProps { queryResultsInfo: QueryResultsInfo; database: string; hasPlanToSvg: boolean; error?: unknown; } export function useQueryInfoMenuItems({ queryResultsInfo, database, hasPlanToSvg, error, }: UseQueryInfoMenuItemsProps) { const [blobUrl, setBlobUrl] = React.useState<string | null>(null); const [getPlanToSvg, {isLoading}] = planToSvgApi.useLazyPlanToSvgQueryQuery(); React.useEffect(() => { return () => { if (blobUrl) { URL.revokeObjectURL(blobUrl); } }; }, [blobUrl]); const items = React.useMemo<DropdownMenuItemWithDescription[][]>(() => { const menuItems: DropdownMenuItemWithDescription[][] = []; const plan = queryResultsInfo.plan; if (plan && hasPlanToSvg) { const handleGetSvg = () => { if (blobUrl) { return Promise.resolve(blobUrl); } return getPlanToSvg({plan, database}) .unwrap() .then((result) => { const blob = new Blob([result], {type: 'image/svg+xml'}); const url = URL.createObjectURL(blob); setBlobUrl(url); return url; }) .catch((err) => { const errorMessage = prepareCommonErrorMessage(err); createToast({ title: i18n('text_error-plan-svg', {error: errorMessage}), name: 'plan-svg-error', theme: 'danger', }); return null; }); }; const handleOpenInNewTab = () => { handleGetSvg().then((url) => { if (url) { window.open(url, '_blank'); } }); }; const handleDownload = () => { handleGetSvg().then((url) => { if (url) { downloadFile(url, 'query-plan.svg'); } }); }; menuItems.push([ { title: i18n('text_open-execution-plan'), description: i18n('text_open-execution-plan_description'), iconStart: ArrowUpRightFromSquare, action: handleOpenInNewTab, }, { title: i18n('text_download'), description: i18n('text_download_description'), iconStart: ArrowDownToLine, action: handleDownload, }, ]); } if (queryResultsInfo) { const handleDiagnosticsDownload = () => { const parsedError = error ? parseQueryError(error) : undefined; const diagnosticsData: DiagnosticsData = { ...queryResultsInfo, database, ...(parsedError && {error: parsedError}), }; createAndDownloadJsonFile( diagnosticsData, `query-diagnostics-${new Date().getTime()}`, ); }; menuItems.push([ { title: i18n('text_diagnostics'), description: i18n('text_diagnostics_description'), iconStart: ArrowDownToLine, action: handleDiagnosticsDownload, }, ]); } return menuItems; }, [queryResultsInfo, hasPlanToSvg, blobUrl, getPlanToSvg, database, error]); return { isLoading, items, }; }