Skip to content

Commit 2dbdb5b

Browse files
committed
feat: add format prop #25
1 parent 9c61204 commit 2dbdb5b

File tree

13 files changed

+224
-76
lines changed

13 files changed

+224
-76
lines changed

ant/src/CronEditor.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export default {
6363
type: Object,
6464
default: () => {
6565
return {
66+
second: 5,
6667
minute: 5,
6768
hour: 4,
6869
day: 4
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { useCron, type CronFormat } from '../cron-core';
4+
5+
type UseCronReturn = ReturnType<typeof useCron>
6+
7+
function cronToString({selected: { value: selected }, period, }:UseCronReturn): string {
8+
const fields = selected.map((seg) => {
9+
const prefix = seg.prefix.value ? seg.prefix.value+' ' : '';
10+
const suffix = seg.suffix.value ? ' '+seg.suffix.value : '';
11+
return prefix+seg.text.value+suffix
12+
}).join(' ')
13+
14+
const prefix = period.prefix.value ? period.prefix.value+' ' : '';
15+
const suffix = period.suffix.value ? ' '+period.suffix.value : '';
16+
return `${prefix}${period.selected.value.text}${suffix} ${fields}`
17+
}
18+
19+
describe('useCron', () => {
20+
it('renders properly', () => {
21+
const tests: {
22+
format: CronFormat,
23+
value: string,
24+
expected: string,
25+
}[] = [
26+
{
27+
format: 'crontab',
28+
value: '* * * * *',
29+
expected: `Every Year in every month on every day and every day of the week at every hour : every minute`
30+
},
31+
{
32+
format: 'quartz',
33+
value: '* * * * * *',
34+
expected: `Every Year in every month on every day and every day of the week at every hour : every minute : every second`
35+
}
36+
]
37+
38+
for(const t of tests) {
39+
const cron = useCron({format: t.format, initialValue: t.value})
40+
expect(cronToString(cron)).toEqual(t.expected)
41+
}
42+
})
43+
44+
it('format option', () => {
45+
const formats: {
46+
value: CronFormat
47+
expectedFields: number
48+
expectedPeriods: number
49+
}[] = [
50+
{
51+
value: 'crontab',
52+
expectedFields: 5,
53+
expectedPeriods: 6
54+
},
55+
{
56+
value: 'quartz',
57+
expectedFields: 6,
58+
expectedPeriods: 7
59+
}
60+
]
61+
62+
for (const format of formats) {
63+
const cron = useCron({ format: format.value })
64+
65+
expect(cron.segments.length).toEqual(format.expectedFields)
66+
expect(cron.period.items.length).toEqual(format.expectedPeriods)
67+
}
68+
})
69+
})

core/src/components/__tests__/select.spec.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,23 @@ describe('select', () => {
5151
}
5252
})
5353

54-
const withTick = async (fn : () => void) => {
54+
const withTick = async (fn: () => void) => {
5555
fn()
5656
await nextTick()
5757
}
5858

59-
const { select, setItems, selected } = useSelect<any, number>({items, multiple: true})
59+
const { select, setItems, selected } = useSelect<any, number>({ items, multiple: true })
6060

61-
let counter = 0;
62-
const expected = [
63-
[0],
64-
[],
65-
[1,2]
66-
]
61+
let counter = 0
62+
const expected = [[0], [], [1, 2]]
6763
watch(selected, (value) => {
68-
expect((value as number[]).sort()).toEqual(expected[counter].sort());
69-
counter++;
64+
expect((value as number[]).sort()).toEqual(expected[counter].sort())
65+
counter++
7066
})
7167

7268
await withTick(() => select(items[0]))
7369
await withTick(() => select(items[0]))
74-
await withTick(() => select({value: 100, text: 'Item-100'})) // ignored
70+
await withTick(() => select({ value: 100, text: 'Item-100' })) // ignored
7571
await withTick(() => setItems([items[1], items[2]]))
7672
await withTick(() => setItems([items[1], items[2]])) // ignored
7773
})

core/src/components/cron-core.ts

Lines changed: 78 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import { FieldWrapper, TextPosition, type Field, type Period } from '../types'
55
import { defaultItems } from '../util'
66
import { useCronSegment } from './cron-segment'
77

8+
export type CronFormat = 'crontab' | 'quartz'
9+
810
interface CronOptions {
911
initialValue?: string
1012
locale?: string
1113
fields?: Field[]
1214
periods?: Period[]
1315
customLocale?: Localization
16+
format?: CronFormat
1417
}
1518

1619
function createCron(len: number, seg: string = '*') {
@@ -24,14 +27,17 @@ function isDefined<T>(obj: T | undefined): obj is T {
2427
class DefaultCronOptions {
2528
locale = 'en'
2629

30+
format: CronFormat = 'crontab'
31+
2732
initialValue(len: number, seg: string = '*') {
2833
return createCron(len, seg)
2934
}
3035

31-
fields(locale: string) {
36+
fields(format: CronFormat, locale: string) {
3237
const items = defaultItems(locale)
3338

3439
return [
40+
...(format == 'quartz' ? [{ id: 'second', items: items.secondItems }] : []),
3541
{ id: 'minute', items: items.minuteItems },
3642
{ id: 'hour', items: items.hourItems },
3743
{ id: 'day', items: items.dayItems },
@@ -40,27 +46,34 @@ class DefaultCronOptions {
4046
]
4147
}
4248

43-
periods() {
49+
periods(format: CronFormat) {
50+
const isQuartz = format == 'quartz';
51+
const second = isQuartz ? [{ id: 'q-second', value: [] }] : []
52+
const secondField = isQuartz ? ['second'] : []
53+
const prefix = isQuartz ? 'q-' : '';
54+
4455
return [
45-
{ id: 'minute', value: [] },
46-
{ id: 'hour', value: ['minute'] },
47-
{ id: 'day', value: ['hour', 'minute'] },
48-
{ id: 'week', value: ['dayOfWeek', 'hour', 'minute'] },
49-
{ id: 'month', value: ['day', 'dayOfWeek', 'hour', 'minute'] },
50-
{ id: 'year', value: ['month', 'day', 'dayOfWeek', 'hour', 'minute'] }
56+
...second,
57+
{ id: prefix + 'minute', value: [...secondField] },
58+
{ id: prefix + 'hour', value: ['minute', ...secondField] },
59+
{ id: 'day', value: ['hour', 'minute', ...secondField] },
60+
{ id: 'week', value: ['dayOfWeek', 'hour', 'minute', ...secondField] },
61+
{ id: 'month', value: ['day', 'dayOfWeek', 'hour', 'minute', ...secondField] },
62+
{ id: 'year', value: ['month', 'day', 'dayOfWeek', 'hour', 'minute', ...secondField] }
5163
]
5264
}
5365
}
5466

5567
export function useCron(options: CronOptions) {
5668
const cronDefaults = new DefaultCronOptions()
5769

58-
const locale = options.locale ?? 'en'
59-
const { customLocale, fields = cronDefaults.fields(locale) } = options
70+
const locale = options.locale ?? cronDefaults.locale
71+
const format = options.format ?? cronDefaults.format
72+
const { customLocale, fields = cronDefaults.fields(format, locale) } = options
6073
const initialValue = options.initialValue ?? cronDefaults.initialValue(fields.length)
6174

6275
const l10n = getLocale(locale, customLocale)
63-
const periods = (options.periods ?? cronDefaults.periods()).map((p) => {
76+
const periods = (options.periods ?? cronDefaults.periods(format)).map((p) => {
6477
return {
6578
...p,
6679
text: l10n.getLocaleStr(p.id, TextPosition.Text)
@@ -161,6 +174,9 @@ export const cronProps = {
161174
modelValue: {
162175
type: String
163176
},
177+
format: {
178+
type: String as PropType<CronFormat>
179+
},
164180
locale: {
165181
type: String
166182
},
@@ -176,63 +192,63 @@ export const cronProps = {
176192
}
177193

178194
export const CronCore = defineComponent({
179-
name: 'VueCronCore',
180-
props: cronProps,
181-
emits: ['update:model-value', 'error'],
182-
setup(props, ctx) {
183-
const { cron, error, selected, period } = useCron(props)
184-
185-
watch(cron, (value) => {
186-
ctx.emit('update:model-value', value)
187-
})
195+
name: 'VueCronCore',
196+
props: cronProps,
197+
emits: ['update:model-value', 'error'],
198+
setup(props, ctx) {
199+
const { cron, error, selected, period } = useCron(props)
200+
201+
watch(cron, (value) => {
202+
ctx.emit('update:model-value', value)
203+
})
188204

189-
watch(error, (value) => {
190-
ctx.emit('error', value)
191-
})
205+
watch(error, (value) => {
206+
ctx.emit('error', value)
207+
})
192208

193-
watch(
194-
() => props.modelValue,
195-
(value) => {
196-
if (value) {
197-
cron.value = value
198-
}
209+
watch(
210+
() => props.modelValue,
211+
(value) => {
212+
if (value) {
213+
cron.value = value
199214
}
200-
)
201-
202-
return () => {
203-
const slotProps = {
204-
error: error,
205-
fields: selected.value.map((s) => {
206-
return {
207-
id: s.id,
208-
items: s.items,
209-
cron: s.cron.value,
210-
selectedStr: s.text.value,
211-
events: {
212-
'update:model-value': s.select
213-
},
214-
attrs: {
215-
modelValue: s.selected.value
216-
},
217-
prefix: s.prefix.value,
218-
suffix: s.suffix.value
219-
}
220-
}),
221-
222-
period: {
223-
attrs: {
224-
modelValue: period.selected.value.id
225-
},
215+
}
216+
)
217+
218+
return () => {
219+
const slotProps = {
220+
error: error,
221+
fields: selected.value.map((s) => {
222+
return {
223+
id: s.id,
224+
items: s.items,
225+
cron: s.cron.value,
226+
selectedStr: s.text.value,
226227
events: {
227-
'update:model-value': period.select
228+
'update:model-value': s.select
229+
},
230+
attrs: {
231+
modelValue: s.selected.value
228232
},
229-
items: period.items,
230-
prefix: period.prefix.value,
231-
suffix: period.suffix.value
233+
prefix: s.prefix.value,
234+
suffix: s.suffix.value
232235
}
236+
}),
237+
238+
period: {
239+
attrs: {
240+
modelValue: period.selected.value.id
241+
},
242+
events: {
243+
'update:model-value': period.select
244+
},
245+
items: period.items,
246+
prefix: period.prefix.value,
247+
suffix: period.suffix.value
233248
}
234-
235-
return ctx.slots.default?.(slotProps)
236249
}
250+
251+
return ctx.slots.default?.(slotProps)
237252
}
238-
})
253+
}
254+
})

core/src/components/select.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export function useSelect<T, V>(options: SelectOptions<T, V>) {
162162
selectedStr,
163163
itemRows: splitArray(items, cols),
164164
setItems,
165-
setValues,
165+
setValues
166166
}
167167
}
168168

core/src/locale/de.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ const locale: Localization = {
5757
prefix: '',
5858
text: 'alle {{every.value}} Minuten'
5959
}
60+
},
61+
second: {
62+
'*': { prefix: ':' },
63+
empty: { text: 'jede Sekunde' },
64+
everyX: {
65+
prefix: '',
66+
text: 'alle {{every.value}} Sekunden'
67+
}
6068
}
6169
},
6270
minute: {
@@ -86,7 +94,33 @@ const locale: Localization = {
8694
year: {
8795
prefix: 'Jedes',
8896
text: 'Jahr'
89-
}
97+
},
98+
99+
//quartz format
100+
'q-second': {
101+
text: 'Sekunde'
102+
},
103+
'q-minute': {
104+
text: 'Minute',
105+
second: {
106+
'*': {
107+
prefix: 'und',
108+
},
109+
}
110+
},
111+
'q-hour': {
112+
text: 'Stunde',
113+
minute: {
114+
'*': {
115+
prefix: 'und'
116+
}
117+
},
118+
second: {
119+
'*': {
120+
prefix: 'und'
121+
}
122+
}
123+
},
90124
}
91125

92126
export default locale

0 commit comments

Comments
 (0)