Skip to content

Commit 9321c70

Browse files
committed
feat: improve initial period selection #64
The new implementation finds the first period, which includes all dirty fields. The list of periods is traversed in reverse order.
1 parent 2fcb845 commit 9321c70

File tree

7 files changed

+2599
-1386
lines changed

7 files changed

+2599
-1386
lines changed

.vscode/extensions.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"recommendations": [
33
"Vue.volar",
4+
"vitest.explorer",
45
"Vue.vscode-typescript-vue-plugin",
56
"dbaeumer.vscode-eslint",
67
]

.vscode/settings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"editor.formatOnSave": false,
3-
"jest.autoRun": "off",
43
"eslint.enable": true,
54
"editor.codeActionsOnSave": [
65
"source.organizeImports",
76
"source.fixAll.eslint"
8-
]
7+
],
8+
"vitest.workspaceConfig": "vitest.workspace.ts"
99
}

core/src/components/__tests__/cron-core.spec.ts

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { describe, expect, it } from 'vitest'
22

3-
import type { CronFormat } from '@/types'
3+
import type { CronFormat, Period } from '@/types'
44
import { mount } from '@vue/test-utils'
55
import { defineComponent, nextTick } from 'vue'
6-
import { cronCoreProps, setupCron, useCron } from '../cron-core'
6+
import {
7+
cronCoreProps,
8+
DefaultCronOptions,
9+
findFirstPeriod,
10+
setupCron,
11+
useCron,
12+
} from '../cron-core'
713

814
type UseCronReturn = ReturnType<typeof useCron>
915

@@ -133,3 +139,49 @@ it('setupCron events', async () => {
133139
expect(wrapper.emitted('update:model-value')![0]).toEqual(['5 12 * * *'])
134140
expect(wrapper.emitted('update:period')![0]).toEqual(['month'])
135141
})
142+
143+
describe('findFirstPeriod', () => {
144+
const periods: Period[] = [
145+
{ id: 'week', value: ['dayOfWeek', 'hour', 'minute'] },
146+
{ id: 'month', value: ['day', 'hour', 'minute'] },
147+
{ id: 'day', value: ['hour', 'minute'] },
148+
].reverse()
149+
const options = new DefaultCronOptions()
150+
const fields = options.fields('crontab', 'en')
151+
const qFields = options.fields('quartz', 'en')
152+
153+
const tests = [
154+
{
155+
cron: '0 2 * * 0', // Every Sunday at 02:00
156+
expected: 'week',
157+
},
158+
{
159+
cron: '0 * * * *', // Every hour
160+
expected: 'day',
161+
},
162+
{
163+
cron: '0 2 1 * *', // Every 1st of the month at 02:00
164+
expected: 'month',
165+
},
166+
{
167+
cron: '* * * 1 *', // Every minute in January
168+
expected: undefined,
169+
},
170+
{
171+
cron: '* 0 2 1 * ?',
172+
fields: qFields,
173+
expected: 'month',
174+
},
175+
{
176+
cron: '* * * * *',
177+
periods: options.periods('crontab').reverse(),
178+
expected: 'year',
179+
},
180+
]
181+
182+
for (const t of tests) {
183+
it(t.cron, () => {
184+
expect(findFirstPeriod(t.periods ?? periods, t.cron, t.fields ?? fields)?.id).toBe(t.expected)
185+
})
186+
}
187+
})

core/src/components/cron-core.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function isDefined<T>(obj: T | undefined): obj is T {
3636
return obj !== undefined
3737
}
3838

39-
class DefaultCronOptions {
39+
export class DefaultCronOptions {
4040
locale = 'en'
4141

4242
format: CronFormat = 'crontab'
@@ -117,6 +117,23 @@ class DefaultCronOptions {
117117
}
118118
}
119119

120+
export function findFirstPeriod(
121+
periods: Period[],
122+
cron: string,
123+
fields: Field[],
124+
): Period | undefined {
125+
const segments = cron.split(' ')
126+
if (segments.length !== fields.length) {
127+
return
128+
}
129+
const dirtyFields = fields.filter((_, i) => !['*', '?'].includes(segments[i])).map((f) => f.id)
130+
// find the first period, which includes all dirty fields
131+
return periods.find((p) => {
132+
const visible = new Set(p.value)
133+
return dirtyFields.every((fid) => visible.has(fid))
134+
})
135+
}
136+
120137
export function useCron(options: CronOptions) {
121138
const cronDefaults = new DefaultCronOptions()
122139

@@ -133,7 +150,9 @@ export function useCron(options: CronOptions) {
133150
}
134151
})
135152
const initialPeriod =
136-
periods.find((p) => p.id == options.initialPeriod) ?? periods[periods.length - 1]
153+
(options.initialPeriod ? periods.find((p) => p.id == options.initialPeriod) : undefined) ??
154+
findFirstPeriod([...periods].reverse(), initialValue, fields) ??
155+
periods[periods.length - 1]
137156

138157
const cron = ref(initialValue)
139158
const error = ref('')

0 commit comments

Comments
 (0)