2
0
mirror of https://github.com/tenrok/vue-cron-editor-bootstrap.git synced 2026-06-20 20:10:34 +03:00

refactoring

This commit is contained in:
2023-10-12 09:31:35 +03:00
parent 7b200a750b
commit 5d7e42ab90
32 changed files with 20862 additions and 21646 deletions
+151
View File
@@ -0,0 +1,151 @@
interface MinutesTabUpdatedEvent {
type: 'minutes'
minuteInterval: number
}
interface HourlyTabUpdatedEvent {
type: 'hourly'
minutes: number
hourInterval: number
}
interface DailyTabUpdatedEvent {
type: 'daily'
minutes: number
hours: number
dayInterval: number
}
interface WeeklyTabUpdatedEvent {
type: 'weekly'
minutes: number
hours: number
days: string[]
}
interface MonthlyTabUpdatedEvent {
type: 'monthly'
minutes: number
hours: number
day: number
monthInterval: number
}
interface AdvancedTabUpdatedEvent {
type: 'advanced'
cronExpression: string
}
export type TabUpdatedEvent =
| MinutesTabUpdatedEvent
| HourlyTabUpdatedEvent
| DailyTabUpdatedEvent
| WeeklyTabUpdatedEvent
| MonthlyTabUpdatedEvent
| AdvancedTabUpdatedEvent
export type TabKey = TabUpdatedEvent[keyof TabUpdatedEvent]
export const buildExpression = (event: TabUpdatedEvent): string => {
if (event.type === 'minutes') {
return `*/${event.minuteInterval} * * * *`
}
if (event.type === 'hourly') {
return `${event.minutes} */${event.hourInterval} * * *`
}
if (event.type === 'daily') {
return `${event.minutes} ${event.hours} */${event.dayInterval} * *`
}
if (event.type === 'weekly') {
if ([0, 7].includes(event.days.length)) {
return `${event.minutes} ${event.hours} * * *`
} else {
return (
`${event.minutes} ${event.hours} * * ` +
`${event.days
.filter(d => d)
.sort()
.join()}`
)
}
}
if (event.type === 'monthly') {
return `${event.minutes} ${event.hours} ${event.day} */${event.monthInterval} *`
}
if (event.type === 'advanced') {
return event.cronExpression
}
throw `unknown event type: ${event}`
}
export const parseExpression = (expression: string): TabUpdatedEvent => {
let groups = null
if (expression!.split(' ').length != 5) {
return {
type: 'advanced',
cronExpression: expression,
}
}
if ((groups = expression.match(/^\*\/(\d+) \* \* \* \*$/))) {
return {
type: 'minutes',
minuteInterval: Number(groups[1]),
}
}
if ((groups = expression.match(/^(\d+) \*\/(\d+) \* \* \*$/))) {
return {
type: 'hourly',
minutes: Number(groups[1]),
hourInterval: Number(groups[2]),
}
}
if ((groups = expression.match(/^(\d+) (\d+) \*\/(\d+) \* \*$/))) {
return {
type: 'daily',
minutes: Number(groups[1]),
hours: Number(groups[2]),
dayInterval: Number(groups[3]),
}
}
if ((groups = expression.match(/^(\d+) (\d+) \* \* (\d)(,\d)?(,\d)?(,\d)?(,\d)?(,\d)?(,\d)?$/))) {
const optionalDaysBeginIndex = 4
const matchesEndIndex = 10
return {
type: 'weekly',
minutes: Number(groups[1]),
hours: Number(groups[2]),
days: [groups[3]].concat(
groups
.slice(optionalDaysBeginIndex, matchesEndIndex)
.map(d => d && d.replace(/,/, ''))
.filter(d => d)
),
}
}
if ((groups = expression.match(/^(\d+) (\d+) (\d+) \*\/(\d+) \*$/))) {
return {
type: 'monthly',
minutes: Number(groups[1]),
hours: Number(groups[2]),
day: Number(groups[3]),
monthInterval: Number(groups[4]),
}
}
return {
type: 'advanced',
cronExpression: expression,
}
}
+63
View File
@@ -0,0 +1,63 @@
export const defaultLocales: Record<string, Record<string, string>> = {
en: {
every: 'Every',
mminutes: 'minute(s)',
hoursOnMinute: 'hour(s) on minute',
daysAt: 'day(s) at',
at: 'at',
onThe: 'On the',
dayOfEvery: 'day, of every',
monthsAt: 'month(s), at',
// everyDay: 'Every',
mon: 'Mon',
tue: 'Tue',
wed: 'Wed',
thu: 'Thu',
fri: 'Fri',
sat: 'Sat',
sun: 'Sun',
// hasToBeBetween: 'Has to be between',
// and: 'and',
minutes: 'MINUTES',
hourly: 'HOURLY',
daily: 'DAILY',
weekly: 'WEEKLY',
monthly: 'MONTHLY',
advanced: 'ADVANCED',
cronExpression: 'cron expression:',
onlyOn: 'Only on',
},
pl: {
every: 'Co',
mminutes: 'minut',
hoursOnMinute: 'godzin w minucie',
daysAt: 'dni o',
at: 'o',
onThe: '',
dayOfEvery: 'dzień miesiąca, co',
monthsAt: 'miesięcy, o godzinie',
// everyDay: 'W każdy',
mon: 'Pon',
tue: 'Wt',
wed: 'Śr',
thu: 'Czw',
fri: 'Pt',
sat: 'So',
sun: 'Nie',
// hasToBeBetween: 'Wymagana wartość pomiędzy',
// and: 'i',
minutes: 'Minuty',
hourly: 'Godziny',
daily: 'Dni',
weekly: 'Tygodnie',
monthly: 'Miesiące',
advanced: 'Zaawansowane',
cronExpression: 'Wyrażenie cron:',
onlyOn: 'Co',
},
}
export function createI18n(customLocales: Record<string, Record<string, string>>, locale: string): Record<string, string> {
const allLocales = { ...defaultLocales, ...customLocales }
return allLocales[locale]
}
+154
View File
@@ -0,0 +1,154 @@
/**
* vueCronEditorMixin
* Core logic of a component.
* Functionality dependent on UI frameworks should be implemented in derived components
*/
import { buildExpression, parseExpression, TabUpdatedEvent, TabKey } from './cronExpressions'
import * as cronValidator from 'cron-validator'
import * as cronstrue from 'cronstrue/i18n'
import { createI18n } from './i18n'
import Vue from 'vue'
const initialData: Record<TabKey, TabUpdatedEvent> = {
minutes: {
type: 'minutes',
minuteInterval: 1,
},
hourly: {
type: 'hourly',
minutes: 0,
hourInterval: 1,
},
daily: {
type: 'daily',
minutes: 0,
hours: 0,
dayInterval: 1,
},
weekly: {
type: 'weekly',
minutes: 0,
hours: 0,
days: ['1'],
},
monthly: {
type: 'monthly',
hours: 0,
minutes: 0,
day: 1,
monthInterval: 1,
},
advanced: {
type: 'advanced',
cronExpression: '',
},
}
interface ComponentData {
editorData: any
currentTab: TabKey
innerValue: string | null
i18n: Record<string, string> | null
}
export default Vue.extend({
props: {
value: { type: String, default: '*/1 * * * *' },
isAdvancedTabVisible: { type: Boolean, default: true },
preserveStateOnSwitchToAdvanced: { type: Boolean, default: false },
locale: { type: String, default: 'en' },
customLocales: { type: Object, default: null },
},
data() {
return <ComponentData>{
innerValue: '*/1 * * * *',
editorData: Object.assign({}, initialData.minutes),
currentTab: 'minutes',
i18n: null,
}
},
computed: {
explanation(): string {
if (!this.innerValue) {
return ''
}
return (cronstrue as any).toString(this.innerValue, {
locale: this.locale,
})
},
},
watch: {
value: {
handler() {
if (this.value == this.innerValue) {
return
}
this.loadDataFromExpression()
},
},
editorData: {
deep: true,
handler(changedData) {
this.updateCronExpression(changedData)
},
},
},
created() {
this.i18n = createI18n(this.customLocales, this.locale)
this.innerValue = this.value
this.loadDataFromExpression()
},
methods: {
translate(key: string) {
return this.i18n![key]
},
loadDataFromExpression() {
const tabData = parseExpression(this.value)
this.editorData = { ...tabData }
this.currentTab = tabData.type
},
updateCronExpression(event: TabUpdatedEvent) {
const cronExpression = buildExpression({ ...event })
if (cronValidator.isValidCron(cronExpression)) {
this.innerValue = cronExpression
this.$emit('input', cronExpression)
} else {
this.innerValue = null
this.$emit('input', null)
}
},
resetToTab(tabKey: TabKey) {
this.currentTab = tabKey
if (this.preserveStateOnSwitchToAdvanced && tabKey === 'advanced') {
this.editorData = {
type: 'advanced',
cronExpression: this.innerValue,
}
return
}
const tabData = parseExpression(this.value)
if (tabKey == tabData.type) {
this.editorData = Object.assign({}, tabData)
return
}
this.editorData = Object.assign({}, initialData[tabKey])
this.updateCronExpression(initialData[tabKey])
},
},
})