1- import React , { useEffect , useState } from 'react' ;
2- import { useDispatch , useSelector } from 'react-redux' ;
1+ import React , { type ReactNode , useEffect , useState } from 'react' ;
2+ import { useDispatch } from 'react-redux' ;
33import cn from 'bem-cn-lite' ;
44import JSONTree from 'react-json-inspector' ;
55
@@ -11,13 +11,15 @@ import EnableFullscreenButton from '../../../../components/EnableFullscreenButto
1111import Fullscreen from '../../../../components/Fullscreen/Fullscreen' ;
1212import { QueryExecutionStatus } from '../../../../components/QueryExecutionStatus' ;
1313
14+ import type { ValueOf } from '../../../../types/common' ;
15+ import type { IQueryResult , QueryErrorResponse } from '../../../../types/store/query' ;
1416import { disableFullscreen } from '../../../../store/reducers/fullscreen' ;
15-
1617import { prepareQueryError } from '../../../../utils/query' ;
18+ import { useTypedSelector } from '../../../../utils/hooks' ;
1719
1820import { PaneVisibilityToggleButtons } from '../../utils/paneVisibilityToggleHelpers' ;
1921
20- import ResultIssues from '../Issues/Issues' ;
22+ import { ResultIssues } from '../Issues/Issues' ;
2123import { QueryDuration } from '../QueryDuration/QueryDuration' ;
2224
2325import './ExecuteResult.scss' ;
@@ -27,31 +29,51 @@ const b = cn('ydb-query-execute-result');
2729const resultOptionsIds = {
2830 result : 'result' ,
2931 stats : 'stats' ,
30- } ;
32+ } as const ;
33+
34+ type SectionID = ValueOf < typeof resultOptionsIds > ;
3135
3236const resultOptions = [
3337 { value : resultOptionsIds . result , content : 'Result' } ,
3438 { value : resultOptionsIds . stats , content : 'Stats' } ,
3539] ;
3640
37- export function ExecuteResult ( props ) {
38- const [ activeSection , setActiveSection ] = useState ( resultOptionsIds . result ) ;
39- const isFullscreen = useSelector ( ( state ) => state . fullscreen ) ;
41+ interface ExecuteResultProps {
42+ textResults : string ;
43+ result : ReactNode ;
44+ stats : IQueryResult [ 'stats' ] | undefined ;
45+ error : string | QueryErrorResponse | undefined ;
46+ copyDisabled ?: boolean ;
47+ isResultsCollapsed ?: boolean ;
48+ onCollapseResults : VoidFunction ;
49+ onExpandResults : VoidFunction ;
50+ }
51+
52+ export function ExecuteResult ( {
53+ textResults,
54+ result,
55+ stats,
56+ error,
57+ copyDisabled,
58+ isResultsCollapsed,
59+ onCollapseResults,
60+ onExpandResults,
61+ } : ExecuteResultProps ) {
62+ const [ activeSection , setActiveSection ] = useState < SectionID > ( resultOptionsIds . result ) ;
63+ const isFullscreen = useTypedSelector ( ( state ) => state . fullscreen ) ;
4064 const dispatch = useDispatch ( ) ;
4165
4266 useEffect ( ( ) => {
4367 return ( ) => {
4468 dispatch ( disableFullscreen ( ) ) ;
4569 } ;
46- } , [ ] ) ;
70+ } , [ dispatch ] ) ;
4771
48- const onSelectSection = ( value ) => {
49- setActiveSection ( value ) ;
72+ const onSelectSection = ( value : string ) => {
73+ setActiveSection ( value as SectionID ) ;
5074 } ;
5175
5276 const renderClipboardButton = ( ) => {
53- const { textResults, copyDisabled} = props ;
54-
5577 return (
5678 < CopyToClipboard
5779 text = { textResults }
@@ -65,7 +87,7 @@ export function ExecuteResult(props) {
6587 const renderStats = ( ) => {
6688 const content = (
6789 < JSONTree
68- data = { props . stats }
90+ data = { stats }
6991 isExpanded = { ( ) => true }
7092 className = { b ( 'inspector' ) }
7193 searchOptions = { {
@@ -86,8 +108,6 @@ export function ExecuteResult(props) {
86108 } ;
87109
88110 const renderResult = ( ) => {
89- const { result} = props ;
90-
91111 return (
92112 < React . Fragment >
93113 { result }
@@ -101,11 +121,11 @@ export function ExecuteResult(props) {
101121 } ;
102122
103123 const renderIssues = ( ) => {
104- const error = props . error ;
105-
106- const hasIssues = error ?. data ?. issues && Array . isArray ( error . data . issues ) ;
124+ if ( ! error ) {
125+ return null ;
126+ }
107127
108- if ( hasIssues ) {
128+ if ( typeof error === 'object' && error . data ?. issues && Array . isArray ( error . data . issues ) ) {
109129 return (
110130 < React . Fragment >
111131 < ResultIssues data = { error . data } />
@@ -120,20 +140,20 @@ export function ExecuteResult(props) {
120140 ) ;
121141 }
122142
123- if ( error ) {
124- return < div className = { b ( 'error' ) } > { prepareQueryError ( error ) } </ div > ;
125- }
143+ const parsedError = typeof error === 'string' ? error : prepareQueryError ( error ) ;
144+
145+ return < div className = { b ( 'error' ) } > { parsedError } </ div > ;
126146 } ;
127147
128148 return (
129149 < React . Fragment >
130150 < div className = { b ( 'controls' ) } >
131151 < div className = { b ( 'controls-right' ) } >
132- < QueryExecutionStatus error = { props . error } />
152+ < QueryExecutionStatus error = { error } />
133153
134- { props . stats && ! props . error && (
154+ { stats && ! error && (
135155 < React . Fragment >
136- < QueryDuration duration = { props . stats ?. DurationUs } />
156+ < QueryDuration duration = { stats ?. DurationUs } />
137157 < Divider />
138158 < RadioButton
139159 options = { resultOptions }
@@ -147,16 +167,16 @@ export function ExecuteResult(props) {
147167 { renderClipboardButton ( ) }
148168 < EnableFullscreenButton />
149169 < PaneVisibilityToggleButtons
150- onCollapse = { props . onCollapseResults }
151- onExpand = { props . onExpandResults }
152- isCollapsed = { props . isResultsCollapsed }
170+ onCollapse = { onCollapseResults }
171+ onExpand = { onExpandResults }
172+ isCollapsed = { isResultsCollapsed }
153173 initialDirection = "bottom"
154174 />
155175 </ div >
156176 </ div >
157177 < div className = { b ( 'result' ) } >
158- { activeSection === resultOptionsIds . result && ! props . error && renderResult ( ) }
159- { activeSection === resultOptionsIds . stats && ! props . error && renderStats ( ) }
178+ { activeSection === resultOptionsIds . result && ! error && renderResult ( ) }
179+ { activeSection === resultOptionsIds . stats && ! error && renderStats ( ) }
160180 { renderIssues ( ) }
161181 </ div >
162182 </ React . Fragment >
0 commit comments