blob: cc1103699bc0d02885ef94174c7d07e11560006a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { useMemo, FC, ReactElement } from 'react';
import { t, styled, useTheme, SupersetTheme } from '@superset-ui/core';
import { Button, DropdownButton } from '@superset-ui/core/components';
import { IconType, Icons } from '@superset-ui/core/components/Icons';
import { detectOS } from 'src/utils/common';
import { QueryButtonProps } from 'src/SqlLab/types';
import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor';
import {
LOG_ACTIONS_SQLLAB_RUN_QUERY,
LOG_ACTIONS_SQLLAB_STOP_QUERY,
} from 'src/logger/LogUtils';
import useLogAction from 'src/logger/useLogAction';
export interface RunQueryActionButtonProps {
queryEditorId: string;
allowAsync: boolean;
queryState?: string;
runQuery: (c?: boolean) => void;
stopQuery: () => void;
overlayCreateAsMenu: ReactElement | null;
}
const buildTextAndIcon = (
shouldShowStopButton: boolean,
selectedText: string | undefined,
theme: SupersetTheme,
): { text: string; icon?: IconType } => {
let text = t('Run');
let icon: IconType | undefined;
if (selectedText) {
text = t('Run selection');
}
if (shouldShowStopButton) {
text = t('Stop');
icon = <Icons.Square iconSize="xs" iconColor={theme.colorIcon} />;
}
return {
text,
icon,
};
};
const onClick = (
shouldShowStopButton: boolean,
allowAsync: boolean,
runQuery: (c?: boolean) => void = () => undefined,
stopQuery = () => {},
logAction: (name: string, payload: Record<string, any>) => void,
): void => {
const eventName = shouldShowStopButton
? LOG_ACTIONS_SQLLAB_STOP_QUERY
: LOG_ACTIONS_SQLLAB_RUN_QUERY;
logAction(eventName, { shortcut: false });
if (shouldShowStopButton) return stopQuery();
if (allowAsync) {
return runQuery(true);
}
return runQuery(false);
};
const StyledButton = styled.span`
button {
line-height: 13px;
// this is to over ride a previous transition built into the component
transition: background-color 0ms;
&:last-of-type {
margin-right: ${({ theme }) => theme.sizeUnit * 2}px;
}
span[name='caret-down'] {
display: flex;
margin-left: ${({ theme }) => theme.sizeUnit * 1}px;
}
}
`;
const RunQueryActionButton = ({
allowAsync = false,
queryEditorId,
queryState,
overlayCreateAsMenu,
runQuery,
stopQuery,
}: RunQueryActionButtonProps) => {
const theme = useTheme();
const logAction = useLogAction({ queryEditorId });
const userOS = detectOS();
const { selectedText, sql } = useQueryEditor(queryEditorId, [
'selectedText',
'sql',
]);
const shouldShowStopBtn =
!!queryState && ['running', 'pending'].indexOf(queryState) > -1;
const ButtonComponent: FC<QueryButtonProps> = overlayCreateAsMenu
? (DropdownButton as FC)
: Button;
const sqlContent = selectedText || sql || '';
const isDisabled = !sqlContent
?.replace(/(\/\*[^*]*\*\/)|(\/\/[^*]*)|(--[^.].*)/gm, '')
.trim();
const stopButtonTooltipText = useMemo(
() =>
userOS === 'MacOS'
? t('Stop running (Ctrl + x)')
: t('Stop running (Ctrl + e)'),
[userOS],
);
const { text, icon } = useMemo(
() => buildTextAndIcon(shouldShowStopBtn, selectedText, theme),
[shouldShowStopBtn, selectedText, theme],
);
return (
<StyledButton>
<ButtonComponent
data-test="run-query-action"
onClick={() =>
onClick(shouldShowStopBtn, allowAsync, runQuery, stopQuery, logAction)
}
disabled={isDisabled}
tooltip={
(!isDisabled &&
(shouldShowStopBtn
? stopButtonTooltipText
: t('Run query (Ctrl + Return)'))) as string
}
cta
{...(overlayCreateAsMenu
? {
overlay: overlayCreateAsMenu,
icon: (
<Icons.DownOutlined
iconColor={
isDisabled ? theme.colorTextDisabled : theme.colorIcon
}
/>
),
trigger: 'click',
}
: {
buttonStyle: shouldShowStopBtn ? 'danger' : 'primary',
icon,
})}
>
{text}
</ButtonComponent>
</StyledButton>
);
};
export default RunQueryActionButton;