import React from 'react' import Radio from '@material-ui/core/Radio' import { JobSpecFormats, JobSpecFormat, getJobSpecFormat, isJson, isToml, getTaskList, } from './utils' import { ApiResponse } from 'utils/json-api-client' import Button from 'components/Button' import * as api from 'api' import { useDispatch } from 'react-redux' import { OcrJobSpecRequest, OcrJobSpec, JobSpecRequest, } from 'core/store/models' import { JobSpec } from 'core/store/presenters' import BaseLink from 'components/BaseLink' import ErrorMessage from 'components/Notifications/DefaultError' import { notifySuccess, notifyError } from 'actionCreators' import * as storage from 'utils/local-storage' import Content from 'components/Content' import { TextField, Grid, Card, CardContent, FormControlLabel, FormControl, FormLabel, RadioGroup, Divider, CardHeader, CircularProgress, Typography, } from '@material-ui/core' import { createStyles, withStyles, WithStyles, Theme, } from '@material-ui/core/styles' import { useLocation, useHistory } from 'react-router-dom' import { TaskSpec } from 'core/store/models' import TaskListDag from './TaskListDag' import TaskList from 'components/Jobs/TaskList' import { Stratify } from './parseDot' const jobSpecFormatList = [JobSpecFormats.JSON, JobSpecFormats.TOML] export const SELECTED_FORMAT = 'persistSpec.format' export const PERSIST_SPEC = 'persistSpec.' const styles = (theme: Theme) => createStyles({ card: { marginBottom: theme.spacing.unit * 3, }, loader: { position: 'absolute', }, emptyTasks: { padding: theme.spacing.unit * 3, }, }) const SuccessNotification = ({ id }: { id: string }) => ( <> Successfully created job{' '} {id} ) export function validate({ format, value, }: { format: JobSpecFormats value: string }) { if (value.trim() === '') { return false } else if (format === JobSpecFormats.JSON && isJson({ value })) { return true } else if (format === JobSpecFormats.TOML && isToml({ value })) { return true } else { return false } } function apiCall({ format, value, }: { format: JobSpecFormats value: string }): Promise> { if (format === JobSpecFormats.JSON) { const definition: JobSpecRequest = JSON.parse(value) return api.v2.specs.createJobSpec(definition) } if (format === JobSpecFormats.TOML) { const definition: OcrJobSpecRequest = { toml: value } return api.v2.ocrSpecs.createJobSpec(definition) } return Promise.reject('Invalid format') } function getInitialValues({ query, }: { query: string }): { jobSpec: string; format: JobSpecFormats } { const params = new URLSearchParams(query) const queryJobSpec = params.get('definition') as string const queryJobSpecFormat = getJobSpecFormat({ value: queryJobSpec, }) || JobSpecFormats.JSON if (queryJobSpec) { storage.set(`${PERSIST_SPEC}${queryJobSpecFormat}`, queryJobSpec) return { jobSpec: queryJobSpec, format: queryJobSpecFormat, } } const lastOpenedFormat = JobSpecFormats[params.get('format')?.toUpperCase() as JobSpecFormat] || storage.get(SELECTED_FORMAT) || JobSpecFormats.JSON const lastOpenedJobSpec = storage.get(`${PERSIST_SPEC}${lastOpenedFormat}`) || '' return { jobSpec: lastOpenedJobSpec, format: lastOpenedFormat, } } export const New = ({ classes, }: { classes: WithStyles['classes'] }) => { const location = useLocation() const [initialValues] = React.useState(() => getInitialValues({ query: location.search, }), ) const [format, setFormat] = React.useState( initialValues.format, ) const [value, setValue] = React.useState(initialValues.jobSpec) const [valid, setValid] = React.useState(true) const [loading, setLoading] = React.useState(false) const [tasks, setTasks] = React.useState(() => getTaskList({ value: initialValues.jobSpec }), ) const dispatch = useDispatch() const history = useHistory() React.useEffect(() => { const timeout = setTimeout(() => setTasks(getTaskList({ value })), 500) return () => clearTimeout(timeout) }, [value, setTasks]) function handleFormat(_event: React.ChangeEvent<{}>, format: string) { setValue(storage.get(`${PERSIST_SPEC}${format}`) || '') setFormat(format as JobSpecFormats) storage.set(SELECTED_FORMAT, format) setValid(true) history.replace({ search: `?format=${format}`, }) } function handleValue(event: React.ChangeEvent) { setValue(event.target.value) storage.set(`${PERSIST_SPEC}${format}`, event.target.value) setValid(true) } async function handleSubmit(event: React.FormEvent) { event.preventDefault() const isValid = validate({ format, value }) setValid(isValid) if (isValid) { setLoading(true) apiCall({ format, value, }) .then(({ data }) => { dispatch(notifySuccess(SuccessNotification, data)) }) .catch((error) => { dispatch(notifyError(ErrorMessage, error)) setValid(false) }) .finally(() => { setLoading(false) }) } } return (
Job Spec Format {jobSpecFormatList.map((format) => ( } label={format} /> ))} Job Spec
{tasks.format === JobSpecFormats.JSON && tasks.list && ( )} {tasks.format === JobSpecFormats.TOML && tasks.list && ( )} {!tasks.list && ( Tasks not found )}
) } export default withStyles(styles)(New)