blob: 0e08f7827da4e4a304c12a2d1d728f9ce50ccd68 [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 React, { FunctionComponent, useState } from 'react';
import SchemaForm, { FormProps, FormValidation } from 'react-jsonschema-form';
import { Row, Col, Input, TextArea } from 'src/common/components';
import { t, styled } from '@superset-ui/core';
import * as chrono from 'chrono-node';
import ModalTrigger from 'src/components/ModalTrigger';
import { Form, FormItem } from 'src/components/Form';
import './ScheduleQueryButton.less';
import Button from 'src/components/Button';
const validators = {
greater: (a: number, b: number) => a > b,
greater_equal: (a: number, b: number) => a >= b,
less: (a: number, b: number) => a < b,
less_equal: (a: number, b: number) => a <= b,
};
const getJSONSchema = () => {
const jsonSchema = window.featureFlags.SCHEDULED_QUERIES?.JSONSCHEMA;
// parse date-time into usable value (eg, 'today' => `new Date()`)
if (jsonSchema) {
Object.entries(jsonSchema.properties).forEach(
([key, value]: [string, any]) => {
if (value.default && value.format === 'date-time') {
jsonSchema.properties[key] = {
...value,
default: chrono.parseDate(value.default).toISOString(),
};
}
},
);
return jsonSchema;
}
return {};
};
const getUISchema = () => window.featureFlags.SCHEDULED_QUERIES?.UISCHEMA;
const getValidationRules = () =>
window.featureFlags.SCHEDULED_QUERIES?.VALIDATION || [];
const getValidator = () => {
const rules: any = getValidationRules();
return (formData: Record<string, any>, errors: FormValidation) => {
rules.forEach((rule: any) => {
const test = validators[rule.name];
const args = rule.arguments.map((name: string) => formData[name]);
const container = rule.container || rule.arguments.slice(-1)[0];
if (!test(...args)) {
errors[container].addError(rule.message);
}
});
return errors;
};
};
interface ScheduleQueryButtonProps {
defaultLabel?: string;
sql: string;
schema?: string;
dbId: number;
animation?: boolean;
onSchedule?: Function;
scheduleQueryWarning: string | null;
disabled: boolean;
tooltip: string;
}
const StyledRow = styled(Row)`
padding-bottom: ${({ theme }) => theme.gridUnit * 2}px;
`;
export const StyledButtonComponent = styled(Button)`
background: none;
text-transform: none;
padding: 0px;
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
font-weight: ${({ theme }) => theme.typography.weights.normal};
&:disabled {
background: none;
color: rgba(0, 0, 0, 0.85);
&:hover {
background: none;
color: rgba(0, 0, 0, 0.85);
}
}
`;
const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({
defaultLabel = t('Undefined'),
sql,
schema,
dbId,
onSchedule = () => {},
scheduleQueryWarning,
tooltip,
disabled = false,
}) => {
const [description, setDescription] = useState('');
const [label, setLabel] = useState(defaultLabel);
const [showSchedule, setShowSchedule] = useState(false);
let saveModal: ModalTrigger | null;
const onScheduleSubmit = ({
formData,
}: {
formData: Omit<FormProps<Record<string, any>>, 'schema'>;
}) => {
const query = {
label,
description,
db_id: dbId,
schema,
sql,
extra_json: JSON.stringify({ schedule_info: formData }),
};
onSchedule(query);
saveModal?.close();
};
const renderModalBody = () => (
<Form layout="vertical">
<StyledRow>
<Col xs={24}>
<FormItem label={t('Label')}>
<Input
type="text"
placeholder={t('Label for your query')}
value={label}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
setLabel(event.target.value)
}
/>
</FormItem>
</Col>
</StyledRow>
<StyledRow>
<Col xs={24}>
<FormItem label={t('Description')}>
<TextArea
rows={4}
placeholder={t('Write a description for your query')}
value={description}
onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>
setDescription(event.target.value)
}
/>
</FormItem>
</Col>
</StyledRow>
<Row>
<Col xs={24}>
<div className="json-schema">
<SchemaForm
schema={getJSONSchema()}
uiSchema={getUISchema}
onSubmit={onScheduleSubmit}
validate={getValidator()}
>
<Button
buttonStyle="primary"
htmlType="submit"
css={{ float: 'right' }}
>
Submit
</Button>
</SchemaForm>
</div>
</Col>
</Row>
{scheduleQueryWarning && (
<Row>
<Col xs={24}>
<small>{scheduleQueryWarning}</small>
</Col>
</Row>
)}
</Form>
);
return (
<span className="ScheduleQueryButton">
<ModalTrigger
ref={ref => {
saveModal = ref;
}}
modalTitle={t('Schedule query')}
modalBody={renderModalBody()}
triggerNode={
<StyledButtonComponent
onClick={() => setShowSchedule(!showSchedule)}
buttonSize="small"
buttonStyle="link"
tooltip={tooltip}
disabled={disabled}
>
{t('Schedule')}
</StyledButtonComponent>
}
/>
</span>
);
};
export default ScheduleQueryButton;