11import React from 'react' ;
22
3- import {
4- CircleCheck ,
5- CircleInfo ,
6- CircleQuestionFill ,
7- CircleStop ,
8- CircleXmark ,
9- } from '@gravity-ui/icons' ;
10- import { Icon , Spin , Tooltip } from '@gravity-ui/uikit' ;
3+ import { duration } from '@gravity-ui/date-utils' ;
4+ import { CircleCheckFill , CircleQuestionFill , CircleStop , CircleXmark } from '@gravity-ui/icons' ;
5+ import type { LabelProps , TextProps } from '@gravity-ui/uikit' ;
6+ import { Icon , Label , Spin , Text } from '@gravity-ui/uikit' ;
117
12- import i18n from '../../containers/Tenant/Query/i18n' ;
138import { isQueryCancelledError } from '../../containers/Tenant/Query/utils/isQueryCancelledError' ;
9+ import { selectQueryDuration } from '../../store/reducers/query/query' ;
1410import { cn } from '../../utils/cn' ;
15- import { useChangedQuerySettings } from '../../utils/hooks/useChangedQuerySettings' ;
11+ import { HOUR_IN_SECONDS , SECOND_IN_MS } from '../../utils/constants' ;
12+ import { useTypedSelector } from '../../utils/hooks' ;
1613import { isAxiosError } from '../../utils/response' ;
17- import QuerySettingsDescription from '../QuerySettingsDescription/QuerySettingsDescription' ;
1814
1915import './QueryExecutionStatus.scss' ;
2016
@@ -26,57 +22,83 @@ interface QueryExecutionStatusProps {
2622 loading ?: boolean ;
2723}
2824
29- const QuerySettingsIndicator = ( ) => {
30- const { isIndicatorShown, changedLastExecutionSettingsDescriptions} = useChangedQuerySettings ( ) ;
31-
32- if ( ! isIndicatorShown ) {
33- return null ;
34- }
35-
36- return (
37- < Tooltip
38- openDelay = { 0 }
39- content = {
40- < QuerySettingsDescription
41- prefix = { i18n ( 'banner.query-settings.message' ) }
42- querySettings = { changedLastExecutionSettingsDescriptions }
43- />
44- }
45- >
46- < Icon data = { CircleInfo } className = { b ( 'query-settings-icon' ) } />
47- </ Tooltip >
48- ) ;
49- } ;
50-
5125export const QueryExecutionStatus = ( { className, error, loading} : QueryExecutionStatusProps ) => {
5226 let icon : React . ReactNode ;
5327 let label : string ;
28+ let theme : LabelProps [ 'theme' ] ;
29+ let textColor : TextProps [ 'color' ] ;
30+ const { startTime, endTime} = useTypedSelector ( selectQueryDuration ) ;
31+
32+ const [ queryDuration , setQueryDuration ] = React . useState < number > (
33+ startTime ? ( endTime || Date . now ( ) ) - startTime : 0 ,
34+ ) ;
35+
36+ const isCancelled = isQueryCancelledError ( error ) ;
37+
38+ const setDuration = React . useCallback ( ( ) => {
39+ if ( startTime ) {
40+ const actualEndTime = endTime || Date . now ( ) ;
41+ setQueryDuration ( actualEndTime - startTime ) ;
42+ }
43+ } , [ endTime , startTime ] ) ;
44+
45+ React . useEffect ( ( ) => {
46+ let timerId : ReturnType < typeof setInterval > | undefined ;
47+ setDuration ( ) ;
48+
49+ if ( loading ) {
50+ timerId = setInterval ( setDuration , SECOND_IN_MS ) ;
51+ } else {
52+ clearInterval ( timerId ) ;
53+ }
54+ return ( ) => {
55+ clearInterval ( timerId ) ;
56+ } ;
57+ } , [ loading , setDuration ] ) ;
58+
59+ const formattedQueryDuration = React . useMemo ( ( ) => {
60+ return queryDuration > HOUR_IN_SECONDS * SECOND_IN_MS
61+ ? duration ( queryDuration ) . format ( 'hh:mm:ss' )
62+ : duration ( queryDuration ) . format ( 'mm:ss' ) ;
63+ } , [ queryDuration ] ) ;
5464
5565 if ( loading ) {
66+ theme = 'info' ;
67+ textColor = 'info-heavy' ;
5668 icon = < Spin size = "xs" /> ;
5769 label = 'Running' ;
5870 } else if ( isAxiosError ( error ) && error . code === 'ECONNABORTED' ) {
71+ theme = 'danger' ;
72+ textColor = 'danger-heavy' ;
5973 icon = < Icon data = { CircleQuestionFill } /> ;
6074 label = 'Connection aborted' ;
61- } else if ( isQueryCancelledError ( error ) ) {
62- icon = < Icon data = { CircleStop } /> ;
75+ } else if ( isCancelled ) {
76+ theme = 'warning' ;
77+ textColor = 'warning-heavy' ;
78+ icon = < Icon data = { CircleStop } className = { b ( 'result-status-icon' , { error : true } ) } /> ;
6379 label = 'Stopped' ;
6480 } else {
6581 const hasError = Boolean ( error ) ;
82+ theme = hasError ? 'danger' : 'success' ;
83+ textColor = hasError ? 'danger-heavy' : 'positive-heavy' ;
6684 icon = (
6785 < Icon
68- data = { hasError ? CircleXmark : CircleCheck }
86+ data = { hasError ? CircleXmark : CircleCheckFill }
6987 className = { b ( 'result-status-icon' , { error : hasError } ) }
7088 />
7189 ) ;
7290 label = hasError ? 'Failed' : 'Completed' ;
7391 }
7492
7593 return (
76- < div className = { b ( null , className ) } >
77- { icon }
78- { label }
79- { isQueryCancelledError ( error ) || loading ? null : < QuerySettingsIndicator /> }
80- </ div >
94+ < Label
95+ theme = { theme }
96+ size = "m"
97+ className = { b ( null , className ) }
98+ icon = { icon }
99+ value = { formattedQueryDuration }
100+ >
101+ < Text color = { textColor } > { label } </ Text >
102+ </ Label >
81103 ) ;
82104} ;
0 commit comments