import React from 'react'; import {cancelQueryApi} from '../../../../store/reducers/cancelQuery'; import {selectActiveTabId, selectUserInput} from '../../../../store/reducers/query/query'; import type {QueryAction} from '../../../../types/store/query'; import {cn} from '../../../../utils/cn'; import createToast from '../../../../utils/createToast'; import {useTypedSelector} from '../../../../utils/hooks'; import {QUERY_ACTIONS} from '../../../../utils/query'; import {reachMetricaGoal} from '../../../../utils/yaMetrica'; import {NewSQL} from '../NewSQL/NewSQL'; import {queryExecutionManagerInstance} from '../QueryEditor/utils/queryExecutionManager'; import {SaveQuery} from '../SaveQuery/SaveQuery'; import i18n from '../i18n'; import {EditorButton} from './EditorButton'; import './QueryEditorControls.scss'; const b = cn('ydb-query-editor-controls'); interface QueryEditorControlsProps { isLoading: boolean; isStoppable: boolean; disabled?: boolean; highlightedAction: QueryAction; queryId?: string; database: string; isCurrentQueryStreaming?: boolean; handleGetExplainQueryClick: (text: string) => void; handleGetExplainAnalyzeQueryClick: (text: string) => void; handleSendExecuteClick: (text: string) => void; onSettingsButtonClick: () => void; } const STOP_AUTO_HIDE_TIMEOUT = 5000; type ActionButtonType = 'run' | 'explain' | 'explainAnalyze'; interface ActionButtonProps { type: ActionButtonType; isHighlighted: boolean; isLoading: boolean; isStoppable: boolean; controlsDisabled: boolean; onActionClick: () => void; renderStopButton: (type: ActionButtonType) => React.ReactNode; } const actionButtonComponents = { run: EditorButton.Run, explain: EditorButton.Explain, explainAnalyze: EditorButton.ExplainAnalyze, }; const ActionButton = ({ type, isHighlighted, isLoading, isStoppable, controlsDisabled, onActionClick, renderStopButton, }: ActionButtonProps) => { const ButtonComponent = actionButtonComponents[type]; const button = isStoppable && isLoading && isHighlighted ? ( renderStopButton(type) ) : ( ); return (
{button}
); }; const CANCEL_ERROR_ANIMATION_DURATION = 500; export const QueryEditorControls = ({ disabled, isLoading, isStoppable, highlightedAction, queryId, database, isCurrentQueryStreaming, handleSendExecuteClick, onSettingsButtonClick, handleGetExplainQueryClick, handleGetExplainAnalyzeQueryClick, }: QueryEditorControlsProps) => { const input = useTypedSelector(selectUserInput); const activeTabId = useTypedSelector(selectActiveTabId); const [sendCancelQuery, cancelQueryResponse] = cancelQueryApi.useCancelQueryMutation(); const cancelErrorAnimationRef = React.useRef(null); const [cancelQueryError, setCancelQueryError] = React.useState(false); const onStopButtonClick = React.useCallback(async () => { reachMetricaGoal('stopQuery'); try { if (isCurrentQueryStreaming) { if (!activeTabId) { return; } queryExecutionManagerInstance.abortQuery(activeTabId); } else if (queryId) { await sendCancelQuery({queryId, database}).unwrap(); } } catch { createToast({ name: 'stop-error', title: '', content: i18n('alert_stop-query-error'), theme: 'danger', autoHiding: STOP_AUTO_HIDE_TIMEOUT, }); setCancelQueryError(true); if (cancelErrorAnimationRef.current) { window.clearTimeout(cancelErrorAnimationRef.current); } cancelErrorAnimationRef.current = window.setTimeout(() => { setCancelQueryError(false); }, CANCEL_ERROR_ANIMATION_DURATION); } }, [isCurrentQueryStreaming, queryId, sendCancelQuery, database, activeTabId]); const isRunHighlighted = highlightedAction === QUERY_ACTIONS.execute; const isExplainHighlighted = highlightedAction === QUERY_ACTIONS.explain; const isExplainAnalyzeHighlighted = highlightedAction === QUERY_ACTIONS.explainAnalyze; const onRunButtonClick = React.useCallback(() => { handleSendExecuteClick(input); }, [handleSendExecuteClick, input]); const onExplainButtonClick = React.useCallback(() => { handleGetExplainQueryClick(input); }, [handleGetExplainQueryClick, input]); const onExplainAnalyzeButtonClick = React.useCallback(() => { handleGetExplainAnalyzeQueryClick(input); }, [handleGetExplainAnalyzeQueryClick, input]); React.useEffect(() => { return () => { if (cancelErrorAnimationRef.current) { window.clearTimeout(cancelErrorAnimationRef.current); } }; }, []); const controlsDisabled = disabled || !input; const renderStopButton = (replacedAction: ActionButtonType) => ( ); return (
); };