Skip to content

Commit

Permalink
fix(job): simple schedule control not loading existing cron
Browse files Browse the repository at this point in the history
  • Loading branch information
soofstad committed Feb 2, 2024
1 parent 29e5e58 commit 8420527
Show file tree
Hide file tree
Showing 7 changed files with 368 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -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"
}
}
138 changes: 138 additions & 0 deletions example/app/data/DemoDataSource/recipes/recurringJob.recipe.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
150 changes: 76 additions & 74 deletions packages/dm-core-plugins/src/job/CronJob.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[] {
Expand All @@ -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>(EInterval.HOURLY)
const [hour, setHour] = useState<string>('23')
const [hourStep, setHourStep] = useState<string>('1')
const [minute, setMinute] = useState<string>('30')
const { setCronValues, cronValues, isRegistered, schedule, setSchedule } =
props
const [showAdvanced, setShowAdvanced] = useState<boolean>(false)

const getLabel = () => {
if (interval === 'Weekly') {
if (cronValues.interval === 'Weekly') {
return (
<small>
Will run every sunday at {cronValues.hour + ':' + cronValues.minute}{' '}
O'clock. cron: <code>{schedule.cron}</code>
</small>
)
} else if (cronValues.interval === 'Monthly') {
return (
<small>
Will run on the 1st on every month at{' '}
{cronValues.hour + ':' + cronValues.minute} O'clock. cron:{' '}
<code>{schedule.cron}</code>
</small>
)
} else if (cronValues.interval === 'Daily') {
return (
<small>Will run every sunday at {hour + ':' + minute} O'clock</small>
<small>
Will run at {cronValues.hour + ':' + cronValues.minute} O'clock every
day. cron: <code>{schedule.cron}</code>
</small>
)
} else if (interval === 'Monthly') {
} else if (cronValues.interval === 'Hourly') {
return (
<small>
Will run on the 1st on every month at {hour + ':' + minute} O'clock
Will run every {cronValues.hourStep} hour. cron:{' '}
<code>{schedule.cron}</code>
</small>
)
} else if (interval === 'Daily') {
return <small>Will run at {hour + ':' + minute} O'clock every day</small>
} else if (interval === 'Hourly') {
return <small>Will run every {hourStep} hour</small>
}
}

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 (
<div
style={{
Expand All @@ -113,67 +97,85 @@ export function ConfigureSchedule(props: {
/>
<InputWrapper>
{showAdvanced ? (
<TextField
style={{ maxWidth: '400px' }}
unit='cron'
id='advanced-schedule-syntax'
type='text'
defaultValue={schedule.cron}
onChange={(event: ChangeEvent<HTMLInputElement>) =>
setSchedule({
...schedule,
cron: event?.target.value,
})
}
label='Enter explicit cron syntax'
helperText='minute hour day(month) month day(week)'
/>
<div className={'flex-col'}>
<TextField
style={{ maxWidth: '400px' }}
unit='cron'
id='advanced-schedule-syntax'
type='text'
defaultValue={schedule.cron}
onChange={(event: ChangeEvent<HTMLInputElement>) =>
setSchedule({
...schedule,
cron: event?.target.value,
})
}
label='Enter explicit cron syntax'
helperText='minute hour day(month) month day(week)'
/>
<small style={{ color: 'red' }}>
{' '}
Controls might not show correct values after manually entering
cron syntax
</small>
</div>
) : (
<>
<Autocomplete
options={Object.values(EInterval)}
label={'Interval'}
style={{ maxWidth: '200px' }}
initialSelectedOptions={[interval]}
initialSelectedOptions={[cronValues.interval]}
onInputChange={(label: string) => {
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 && (
<Autocomplete
style={{ maxWidth: '200px' }}
options={generateSelectableTimes().map(
(value: string) => 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 && (
<Autocomplete
style={{ maxWidth: '200px' }}
options={[...Array(12).keys()].map((i) => i + 1)}
initialSelectedOptions={[Number(hourStep)]}
initialSelectedOptions={[Number(cronValues.hourStep)]}
label={'Hour step'}
onInputChange={(step) => setHourStep(step)}
onInputChange={(step) =>
setCronValues({ ...cronValues, hourStep: step })
}
/>
)}
</>
)}
<Button
onClick={() => setShowAdvanced(!showAdvanced)}
onClick={() => {
setShowAdvanced(!showAdvanced)
if (showAdvanced) setCronValues(defaultCronValues())
}}
variant='ghost'
className={showAdvanced ? 'self-center -translate-y-1' : 'self-end'}
>
Expand Down
Loading

0 comments on commit 8420527

Please sign in to comment.