11import React from 'react' ;
22
3- import { ArrowUpRightFromSquare } from '@gravity-ui/icons' ;
4- import { Button , Tooltip } from '@gravity-ui/uikit' ;
3+ import { ArrowDownToLine , ArrowUpRightFromSquare , ChevronDown } from '@gravity-ui/icons' ;
4+ import type { ButtonProps } from '@gravity-ui/uikit' ;
5+ import { Button , DropdownMenu } from '@gravity-ui/uikit' ;
56
67import { planToSvgApi } from '../../../../../../store/reducers/planToSvg' ;
78import type { QueryPlan , ScriptPlan } from '../../../../../../types/api/query' ;
@@ -24,20 +25,42 @@ export function PlanToSvgButton({plan, database}: PlanToSvgButtonProps) {
2425 const [ blobUrl , setBlobUrl ] = React . useState < string | null > ( null ) ;
2526 const [ getPlanToSvg , { isLoading} ] = planToSvgApi . useLazyPlanToSvgQueryQuery ( ) ;
2627
27- const handleClick = React . useCallback ( ( ) => {
28- getPlanToSvg ( { plan, database} )
28+ const handleGetSvg = React . useCallback ( ( ) => {
29+ if ( blobUrl ) {
30+ return Promise . resolve ( blobUrl ) ;
31+ }
32+
33+ return getPlanToSvg ( { plan, database} )
2934 . unwrap ( )
3035 . then ( ( result ) => {
3136 const blob = new Blob ( [ result ] , { type : 'image/svg+xml' } ) ;
3237 const url = URL . createObjectURL ( blob ) ;
3338 setBlobUrl ( url ) ;
3439 setError ( null ) ;
35- window . open ( url , '_blank' ) ;
40+ return url ;
3641 } )
3742 . catch ( ( err ) => {
3843 setError ( JSON . stringify ( err ) ) ;
44+ throw err ;
3945 } ) ;
40- } , [ database , getPlanToSvg , plan ] ) ;
46+ } , [ database , getPlanToSvg , plan , blobUrl ] ) ;
47+
48+ const handleOpenInNewTab = React . useCallback ( ( ) => {
49+ handleGetSvg ( ) . then ( ( url ) => {
50+ window . open ( url , '_blank' ) ;
51+ } ) ;
52+ } , [ handleGetSvg ] ) ;
53+
54+ const handleDownload = React . useCallback ( ( ) => {
55+ handleGetSvg ( ) . then ( ( url ) => {
56+ const link = document . createElement ( 'a' ) ;
57+ link . href = url ;
58+ link . download = 'query-plan.svg' ;
59+ document . body . appendChild ( link ) ;
60+ link . click ( ) ;
61+ document . body . removeChild ( link ) ;
62+ } ) ;
63+ } , [ handleGetSvg ] ) ;
4164
4265 React . useEffect ( ( ) => {
4366 return ( ) => {
@@ -47,21 +70,34 @@ export function PlanToSvgButton({plan, database}: PlanToSvgButtonProps) {
4770 } ;
4871 } , [ blobUrl ] ) ;
4972
50- return (
51- < Tooltip
52- content = { error ? i18n ( 'text_error-plan-svg' , { error} ) : i18n ( 'text_open-plan-svg' ) }
53- >
73+ const items = [
74+ {
75+ text : i18n ( 'text_open-new-tab' ) ,
76+ icon : < ArrowUpRightFromSquare /> ,
77+ action : handleOpenInNewTab ,
78+ } ,
79+ {
80+ text : i18n ( 'text_download' ) ,
81+ icon : < ArrowDownToLine /> ,
82+ action : handleDownload ,
83+ } ,
84+ ] ;
85+
86+ const renderSwitcher = ( props : ButtonProps ) => {
87+ return (
5488 < Button
5589 view = { getButtonView ( error , isLoading ) }
5690 loading = { isLoading }
57- onClick = { handleClick }
5891 disabled = { isLoading }
92+ { ...props }
5993 >
6094 { i18n ( 'text_plan-svg' ) }
6195 < Button . Icon >
62- < ArrowUpRightFromSquare />
96+ < ChevronDown />
6397 </ Button . Icon >
6498 </ Button >
65- </ Tooltip >
66- ) ;
99+ ) ;
100+ } ;
101+
102+ return < DropdownMenu renderSwitcher = { renderSwitcher } items = { items } /> ;
67103}
0 commit comments