123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- import {Component, Fragment} from 'react';
- import {Observer} from 'mobx-react';
- import Access from 'sentry/components/acl/access';
- import Field from 'sentry/components/forms/field';
- import Form from 'sentry/components/forms/form';
- import FormModel from 'sentry/components/forms/model';
- import NumberField from 'sentry/components/forms/numberField';
- import SelectField from 'sentry/components/forms/selectField';
- import TextCopyInput from 'sentry/components/forms/textCopyInput';
- import TextField from 'sentry/components/forms/textField';
- import {Panel, PanelBody, PanelHeader} from 'sentry/components/panels';
- import {t, tct} from 'sentry/locale';
- import {PageFilters, Project, SelectValue} from 'sentry/types';
- import withPageFilters from 'sentry/utils/withPageFilters';
- import withProjects from 'sentry/utils/withProjects';
- import {Monitor, MonitorConfig, MonitorTypes, ScheduleType} from './types';
- const SCHEDULE_TYPES: SelectValue<ScheduleType>[] = [
- {value: 'crontab', label: 'Crontab'},
- {value: 'interval', label: 'Interval'},
- ];
- const MONITOR_TYPES: SelectValue<MonitorTypes>[] = [
- {value: 'cron_job', label: 'Cron Job'},
- ];
- const INTERVALS: SelectValue<string>[] = [
- {value: 'minute', label: 'minute(s)'},
- {value: 'hour', label: 'hour(s)'},
- {value: 'day', label: 'day(s)'},
- {value: 'week', label: 'week(s)'},
- {value: 'month', label: 'month(s)'},
- {value: 'year', label: 'year(s)'},
- ];
- type Props = {
- apiEndpoint: string;
- apiMethod: Form['props']['apiMethod'];
- onSubmitSuccess: Form['props']['onSubmitSuccess'];
- projects: Project[];
- selection: PageFilters;
- monitor?: Monitor;
- };
- type TransformedData = {
- config?: Partial<MonitorConfig>;
- };
- function transformData(_data: Record<string, any>, model: FormModel) {
- return model.fields.toJSON().reduce<TransformedData>((data, [k, v]) => {
- if (k.indexOf('config.') !== 0) {
- data[k] = v;
- return data;
- }
- if (!data.config) {
- data.config = {};
- }
- if (k === 'config.schedule.frequency' || k === 'config.schedule.interval') {
- if (!Array.isArray(data.config.schedule)) {
- data.config.schedule = [null, null];
- }
- }
- if (k === 'config.schedule.frequency') {
- data.config!.schedule![0] = parseInt(v as string, 10);
- } else if (k === 'config.schedule.interval') {
- data.config!.schedule![1] = v;
- } else {
- data.config[k.substr(7)] = v;
- }
- return data;
- }, {});
- }
- class MonitorForm extends Component<Props> {
- form = new FormModel({transformData});
- formDataFromConfig(type: MonitorTypes, config: MonitorConfig) {
- const rv = {};
- switch (type) {
- case 'cron_job':
- rv['config.schedule_type'] = config.schedule_type;
- rv['config.checkin_margin'] = config.checkin_margin;
- rv['config.max_runtime'] = config.max_runtime;
- switch (config.schedule_type) {
- case 'interval':
- rv['config.schedule.frequency'] = config.schedule[0];
- rv['config.schedule.interval'] = config.schedule[1];
- break;
- case 'crontab':
- default:
- rv['config.schedule'] = config.schedule;
- }
- break;
- default:
- }
- return rv;
- }
- render() {
- const {monitor} = this.props;
- const selectedProjectId = this.props.selection.projects[0];
- const selectedProject = selectedProjectId
- ? this.props.projects.find(p => p.id === selectedProjectId + '')
- : null;
- return (
- <Access access={['project:write']}>
- {({hasAccess}) => (
- <Form
- allowUndo
- requireChanges
- apiEndpoint={this.props.apiEndpoint}
- apiMethod={this.props.apiMethod}
- model={this.form}
- initialData={
- monitor
- ? {
- name: monitor.name,
- type: monitor.type,
- project: monitor.project.slug,
- ...this.formDataFromConfig(monitor.type, monitor.config),
- }
- : {
- project: selectedProject ? selectedProject.slug : null,
- }
- }
- onSubmitSuccess={this.props.onSubmitSuccess}
- >
- <Panel>
- <PanelHeader>{t('Details')}</PanelHeader>
- <PanelBody>
- {monitor && (
- <Field label={t('ID')}>
- <div className="controls">
- <TextCopyInput>{monitor.id}</TextCopyInput>
- </div>
- </Field>
- )}
- <SelectField
- name="project"
- label={t('Project')}
- disabled={!hasAccess}
- options={this.props.projects
- .filter(p => p.isMember)
- .map(p => ({value: p.slug, label: p.slug}))}
- required
- />
- <TextField
- name="name"
- placeholder={t('My Cron Job')}
- label={t('Name')}
- disabled={!hasAccess}
- required
- />
- </PanelBody>
- </Panel>
- <Panel>
- <PanelHeader>{t('Config')}</PanelHeader>
- <PanelBody>
- <SelectField
- name="type"
- label={t('Type')}
- disabled={!hasAccess}
- options={MONITOR_TYPES}
- required
- />
- <Observer>
- {() => {
- switch (this.form.getValue('type')) {
- case 'cron_job':
- return (
- <Fragment>
- <NumberField
- name="config.max_runtime"
- label={t('Max Runtime')}
- disabled={!hasAccess}
- help={t(
- "The maximum runtime (in minutes) a check-in is allowed before it's marked as a failure."
- )}
- placeholder="e.g. 30"
- />
- <SelectField
- name="config.schedule_type"
- label={t('Schedule Type')}
- disabled={!hasAccess}
- options={SCHEDULE_TYPES}
- required
- />
- </Fragment>
- );
- default:
- return null;
- }
- }}
- </Observer>
- <Observer>
- {() => {
- switch (this.form.getValue('config.schedule_type')) {
- case 'crontab':
- return (
- <Fragment>
- <TextField
- name="config.schedule"
- label={t('Schedule')}
- disabled={!hasAccess}
- placeholder="*/5 * * * *"
- required
- help={tct(
- 'Changes to the schedule will apply on the next check-in. See [link:Wikipedia] for crontab syntax.',
- {
- link: <a href="https://en.wikipedia.org/wiki/Cron" />,
- }
- )}
- />
- <NumberField
- name="config.checkin_margin"
- label={t('Check-in Margin')}
- disabled={!hasAccess}
- help={t(
- "The margin (in minutes) a check-in is allowed to exceed it's scheduled window before being treated as missed."
- )}
- placeholder="e.g. 30"
- />
- </Fragment>
- );
- case 'interval':
- return (
- <Fragment>
- <NumberField
- name="config.schedule.frequency"
- label={t('Frequency')}
- disabled={!hasAccess}
- placeholder="e.g. 1"
- required
- />
- <SelectField
- name="config.schedule.interval"
- label={t('Interval')}
- disabled={!hasAccess}
- options={INTERVALS}
- required
- />
- <NumberField
- name="config.checkin_margin"
- label={t('Check-in Margin')}
- disabled={!hasAccess}
- help={t(
- "The margin (in minutes) a check-in is allowed to exceed it's scheduled window before being treated as missed."
- )}
- placeholder="e.g. 30"
- />
- </Fragment>
- );
- default:
- return null;
- }
- }}
- </Observer>
- </PanelBody>
- </Panel>
- </Form>
- )}
- </Access>
- );
- }
- }
- export default withPageFilters(withProjects(MonitorForm));
|