diff --git a/example/app/data/DemoDataSource/plugins/job/recurringReverseJob.json b/example/app/data/DemoDataSource/plugins/job/recurringReverseJob.json new file mode 100644 index 000000000..b5470ffac --- /dev/null +++ b/example/app/data/DemoDataSource/plugins/job/recurringReverseJob.json @@ -0,0 +1,29 @@ +{ + "_id": "6303cc68-4b9f-40a9-bd4c-a48c35815e06", + "name": "recurringExampleJob", + "label": "Recurring example job", + "type": "JOBCORE:RecurringJob", + "status": "not started", + "schedule": { + "type": "JOBCORE:CronJob", + "cron": "30 */1 * * *", + "runs": [] + }, + "applicationInput": { + "name": "exampleJob", + "type": "JOBCORE:Job", + "status": "not started", + "applicationInput": { + "type": "CORE:Reference", + "address": "dmss://DemoDataSource/$5203cc68-4b9f-40a9-bd4c-a48c35815e06", + "referenceType": "link" + }, + "label": "Example job", + "runner": { + "type": "JOBCORE:ReverseDescription" + } + }, + "runner": { + "type": "JOBCORE:RecurringJobHandler" + } +} diff --git a/example/app/data/DemoDataSource/recipes/recurringJob.recipe.json b/example/app/data/DemoDataSource/recipes/recurringJob.recipe.json new file mode 100644 index 000000000..04d9c8cdc --- /dev/null +++ b/example/app/data/DemoDataSource/recipes/recurringJob.recipe.json @@ -0,0 +1,138 @@ +{ + "type": "CORE:RecipeLink", + "_blueprintPath_": "JOBCORE:RecurringJob", + "initialUiRecipe": { + "name": "Dashboard", + "type": "CORE:UiRecipe", + "config": { + "type": "PLUGINS:dm-core-plugins/grid/GridPluginConfig", + "items": [ + { + "type": "PLUGINS:dm-core-plugins/grid/GridItem", + "gridArea": { + "type": "PLUGINS:dm-core-plugins/grid/GridArea", + "columnEnd": 1, + "columnStart": 1, + "rowEnd": 1, + "rowStart": 1 + }, + "title": "Edit job", + "viewConfig": { + "type": "CORE:InlineRecipeViewConfig", + "recipe": { + "name": "Job Edit", + "type": "CORE:UiRecipe", + "config": { + "type": "PLUGINS:dm-core-plugins/form/FormInput", + "attributes": [ + { + "name": "uid", + "type": "PLUGINS:dm-core-plugins/form/fields/StringField", + "readOnly": true + }, + { + "name": "started", + "type": "PLUGINS:dm-core-plugins/form/fields/StringField", + "readOnly": true + }, + { + "name": "stopped", + "type": "PLUGINS:dm-core-plugins/form/fields/StringField", + "readOnly": true + }, + { + "name": "ended", + "type": "PLUGINS:dm-core-plugins/form/fields/StringField", + "readOnly": true, + "widget": "DateTimeWidget" + }, + { + "name": "status", + "type": "PLUGINS:dm-core-plugins/form/fields/StringField", + "readOnly": true + }, + { + "name": "triggeredBy", + "type": "PLUGINS:dm-core-plugins/form/fields/StringField", + "readOnly": true + }, + { + "name": "outputTarget", + "type": "PLUGINS:dm-core-plugins/form/fields/StringField", + "widget": "EntityPickerWidget" + }, + { + "name": "applicationInput", + "type": "PLUGINS:dm-core-plugins/form/fields/ObjectField", + "showExpanded": false + }, + { + "name": "runner", + "type": "PLUGINS:dm-core-plugins/form/fields/ObjectField", + "searchByType": true, + "showExpanded": false + } + ], + "fields": [ + "uid", + "name", + "label", + "triggeredBy", + "status", + "started", + "stopped", + "ended", + "outputTarget", + "applicationInput", + "runner" + ] + }, + "plugin": "@development-framework/dm-core-plugins/form" + } + } + }, + { + "type": "PLUGINS:dm-core-plugins/grid/GridItem", + "gridArea": { + "type": "PLUGINS:dm-core-plugins/grid/GridArea", + "columnEnd": 1, + "columnStart": 1, + "rowEnd": 2, + "rowStart": 2 + }, + "title": "Control job", + "viewConfig": { + "type": "CORE:InlineRecipeViewConfig", + "recipe": { + "name": "job-control", + "type": "CORE:UiRecipe", + "config": { + "type": "PLUGINS:dm-core-plugins/job/ControlConfig", + "runnerTemplates": [ + { + "type": "PLUGINS:dm-core-plugins/common/Template", + "label": "Hello world", + "path": "dmss://DemoDataSource/plugins/job/helloWorldLocalContainerRunner" + }, + { + "type": "PLUGINS:dm-core-plugins/common/Template", + "label": "Reverse description", + "path": "dmss://DemoDataSource/plugins/job/reverseDescriptionRunner" + } + ] + }, + "plugin": "@development-framework/dm-core-plugins/job" + } + } + } + ], + "showItemBorders": true, + "size": { + "type": "PLUGINS:dm-core-plugins/grid/GridSize", + "columns": 1, + "rows": 2 + } + }, + "plugin": "@development-framework/dm-core-plugins/grid" + } +} diff --git a/packages/dm-core-plugins/src/job/CronJob.tsx b/packages/dm-core-plugins/src/job/CronJob.tsx index 1d9a2c5fc..15d45cbd4 100644 --- a/packages/dm-core-plugins/src/job/CronJob.tsx +++ b/packages/dm-core-plugins/src/job/CronJob.tsx @@ -5,16 +5,11 @@ import { TextField, Typography, } from '@equinor/eds-core-react' -import { ChangeEvent, useEffect, useState } from 'react' +import { ChangeEvent, useState } from 'react' import styled from 'styled-components' import DateRangePicker from './DateRangePicker' - -enum EInterval { - HOURLY = 'Hourly', - DAILY = 'Daily', - WEEKLY = 'Weekly', - MONTHLY = 'Monthly', -} +import { EInterval, TCronValues } from './common' +import { defaultCronValues } from './templateEntities' // Creates a list like ["00:00",...,"24:00"] function generateSelectableTimes(): string[] { @@ -34,60 +29,49 @@ const InputWrapper = styled.div` export function ConfigureSchedule(props: { isRegistered: boolean - // TODO: Export TCronJob from dm-core + setCronValues: (s: TCronValues) => void + cronValues: TCronValues setSchedule: (s: TSchedule) => void schedule: TSchedule readOnly: boolean // TODO: Implement this }) { - const { setSchedule, schedule, isRegistered } = props - const [interval, setInterval] = useState(EInterval.HOURLY) - const [hour, setHour] = useState('23') - const [hourStep, setHourStep] = useState('1') - const [minute, setMinute] = useState('30') + const { setCronValues, cronValues, isRegistered, schedule, setSchedule } = + props const [showAdvanced, setShowAdvanced] = useState(false) const getLabel = () => { - if (interval === 'Weekly') { + if (cronValues.interval === 'Weekly') { + return ( + + Will run every sunday at {cronValues.hour + ':' + cronValues.minute}{' '} + O'clock. cron: {schedule.cron} + + ) + } else if (cronValues.interval === 'Monthly') { + return ( + + Will run on the 1st on every month at{' '} + {cronValues.hour + ':' + cronValues.minute} O'clock. cron:{' '} + {schedule.cron} + + ) + } else if (cronValues.interval === 'Daily') { return ( - Will run every sunday at {hour + ':' + minute} O'clock + + Will run at {cronValues.hour + ':' + cronValues.minute} O'clock every + day. cron: {schedule.cron} + ) - } else if (interval === 'Monthly') { + } else if (cronValues.interval === 'Hourly') { return ( - Will run on the 1st on every month at {hour + ':' + minute} O'clock + Will run every {cronValues.hourStep} hour. cron:{' '} + {schedule.cron} ) - } else if (interval === 'Daily') { - return Will run at {hour + ':' + minute} O'clock every day - } else if (interval === 'Hourly') { - return Will run every {hourStep} hour } } - useEffect(() => { - const newMinute = minute - let newHour = hour - let dayOfMonth = '*' - const month = '*' - let dayOfWeek = '*' - - switch (interval) { - case EInterval.WEEKLY: - dayOfMonth = '*' - dayOfWeek = '6' - break - case EInterval.MONTHLY: - dayOfMonth = '1' - break - case EInterval.HOURLY: - newHour = hourStep ? `*/${hourStep}` : '*' - } - setSchedule({ - ...schedule, - cron: `${newMinute} ${newHour} ${dayOfMonth} ${month} ${dayOfWeek}`, - }) - }, [interval, hour, minute, hourStep]) - return (
{showAdvanced ? ( - ) => - setSchedule({ - ...schedule, - cron: event?.target.value, - }) - } - label='Enter explicit cron syntax' - helperText='minute hour day(month) month day(week)' - /> +
+ ) => + setSchedule({ + ...schedule, + cron: event?.target.value, + }) + } + label='Enter explicit cron syntax' + helperText='minute hour day(month) month day(week)' + /> + + {' '} + Controls might not show correct values after manually entering + cron syntax + +
) : ( <> { const chosenIntervalType = Object.entries(EInterval) .filter((l) => l.length > 0 && l[1] === label) .pop() - setInterval( - chosenIntervalType + setCronValues({ + ...cronValues, + interval: chosenIntervalType ? chosenIntervalType[1] - : EInterval.HOURLY - ) + : EInterval.HOURLY, + }) }} /> - {interval !== EInterval.HOURLY && ( + {cronValues.interval !== EInterval.HOURLY && ( value )} label={'Time'} - initialSelectedOptions={[`${hour}:${minute}`]} + initialSelectedOptions={[ + `${cronValues.hour}:${cronValues.minute}`, + ]} onInputChange={(timestamp) => { const [newHour, newMinute] = timestamp.split(':') - setMinute(newMinute) - setHour(newHour) + setCronValues({ + ...cronValues, + minute: newMinute, + hour: newHour, + }) }} /> )} - {interval === EInterval.HOURLY && ( + {cronValues.interval === EInterval.HOURLY && ( i + 1)} - initialSelectedOptions={[Number(hourStep)]} + initialSelectedOptions={[Number(cronValues.hourStep)]} label={'Hour step'} - onInputChange={(step) => setHourStep(step)} + onInputChange={(step) => + setCronValues({ ...cronValues, hourStep: step }) + } /> )} )}