@djangocfg/ui-tools 2.1.130 → 2.1.132
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -1
- package/dist/CronScheduler.client-REXEMXZN.mjs +67 -0
- package/dist/CronScheduler.client-REXEMXZN.mjs.map +1 -0
- package/dist/CronScheduler.client-YJ2SHYNH.cjs +72 -0
- package/dist/CronScheduler.client-YJ2SHYNH.cjs.map +1 -0
- package/dist/chunk-6G72N466.mjs +995 -0
- package/dist/chunk-6G72N466.mjs.map +1 -0
- package/dist/chunk-74JT4UIM.cjs +1015 -0
- package/dist/chunk-74JT4UIM.cjs.map +1 -0
- package/dist/index.cjs +109 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +280 -1
- package/dist/index.d.ts +280 -1
- package/dist/index.mjs +32 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/index.ts +5 -0
- package/src/tools/CronScheduler/CronScheduler.client.tsx +140 -0
- package/src/tools/CronScheduler/CronScheduler.story.tsx +220 -0
- package/src/tools/CronScheduler/components/CronCheatsheet.tsx +101 -0
- package/src/tools/CronScheduler/components/CustomInput.tsx +67 -0
- package/src/tools/CronScheduler/components/DayChips.tsx +130 -0
- package/src/tools/CronScheduler/components/MonthDayGrid.tsx +143 -0
- package/src/tools/CronScheduler/components/SchedulePreview.tsx +103 -0
- package/src/tools/CronScheduler/components/ScheduleTypeSelector.tsx +57 -0
- package/src/tools/CronScheduler/components/TimeSelector.tsx +132 -0
- package/src/tools/CronScheduler/components/index.ts +24 -0
- package/src/tools/CronScheduler/context/CronSchedulerContext.tsx +242 -0
- package/src/tools/CronScheduler/context/hooks.ts +86 -0
- package/src/tools/CronScheduler/context/index.ts +18 -0
- package/src/tools/CronScheduler/index.tsx +91 -0
- package/src/tools/CronScheduler/lazy.tsx +67 -0
- package/src/tools/CronScheduler/types/index.ts +112 -0
- package/src/tools/CronScheduler/utils/cron-builder.ts +100 -0
- package/src/tools/CronScheduler/utils/cron-humanize.ts +218 -0
- package/src/tools/CronScheduler/utils/cron-parser.ts +188 -0
- package/src/tools/CronScheduler/utils/index.ts +12 -0
- package/src/tools/index.ts +36 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses Unix 5-field cron expression into CronSchedulerState
|
|
5
|
+
* Format: minute hour day-of-month month day-of-week
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { CronSchedulerState, ScheduleType, WeekDay, MonthDay } from '../types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parses Unix 5-field cron expression into state
|
|
12
|
+
*
|
|
13
|
+
* @param cron - Cron expression to parse
|
|
14
|
+
* @returns Parsed state or null if invalid
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* parseCron('0 9 * * *')
|
|
18
|
+
* // { type: 'daily', hour: 9, minute: 0, ... }
|
|
19
|
+
*
|
|
20
|
+
* parseCron('30 14 * * 1,3,5')
|
|
21
|
+
* // { type: 'weekly', hour: 14, minute: 30, weekDays: [1, 3, 5], ... }
|
|
22
|
+
*/
|
|
23
|
+
export function parseCron(cron: string): CronSchedulerState | null {
|
|
24
|
+
if (!cron || typeof cron !== 'string') return null;
|
|
25
|
+
|
|
26
|
+
const parts = cron.trim().split(/\s+/);
|
|
27
|
+
|
|
28
|
+
// Unix cron has exactly 5 fields
|
|
29
|
+
if (parts.length !== 5) return null;
|
|
30
|
+
|
|
31
|
+
const [minutePart, hourPart, dayOfMonthPart, monthPart, dayOfWeekPart] = parts;
|
|
32
|
+
|
|
33
|
+
// Parse minute (0-59 or *)
|
|
34
|
+
const minute = parseField(minutePart, 0, 59);
|
|
35
|
+
if (minute === null && minutePart !== '*') return null;
|
|
36
|
+
|
|
37
|
+
// Parse hour (0-23 or *)
|
|
38
|
+
const hour = parseField(hourPart, 0, 23);
|
|
39
|
+
if (hour === null && hourPart !== '*') return null;
|
|
40
|
+
|
|
41
|
+
// Determine schedule type based on field patterns
|
|
42
|
+
const result = detectScheduleType(
|
|
43
|
+
minutePart,
|
|
44
|
+
hourPart,
|
|
45
|
+
dayOfMonthPart,
|
|
46
|
+
monthPart,
|
|
47
|
+
dayOfWeekPart
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
type: result.type,
|
|
52
|
+
hour: hour ?? 0,
|
|
53
|
+
minute: minute ?? 0,
|
|
54
|
+
weekDays: result.weekDays,
|
|
55
|
+
monthDays: result.monthDays,
|
|
56
|
+
customCron: cron,
|
|
57
|
+
isValid: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Detects schedule type from cron fields
|
|
63
|
+
*/
|
|
64
|
+
function detectScheduleType(
|
|
65
|
+
_minutePart: string,
|
|
66
|
+
_hourPart: string,
|
|
67
|
+
dayOfMonthPart: string,
|
|
68
|
+
monthPart: string,
|
|
69
|
+
dayOfWeekPart: string
|
|
70
|
+
): {
|
|
71
|
+
type: ScheduleType;
|
|
72
|
+
weekDays: WeekDay[];
|
|
73
|
+
monthDays: MonthDay[];
|
|
74
|
+
} {
|
|
75
|
+
// Default values
|
|
76
|
+
let type: ScheduleType = 'custom';
|
|
77
|
+
let weekDays: WeekDay[] = [1, 2, 3, 4, 5]; // Mon-Fri
|
|
78
|
+
let monthDays: MonthDay[] = [1];
|
|
79
|
+
|
|
80
|
+
// Daily: M H * * *
|
|
81
|
+
if (dayOfMonthPart === '*' && monthPart === '*' && dayOfWeekPart === '*') {
|
|
82
|
+
type = 'daily';
|
|
83
|
+
}
|
|
84
|
+
// Weekly: M H * * 1,2,3 (or ranges like 1-5)
|
|
85
|
+
else if (dayOfMonthPart === '*' && monthPart === '*' && dayOfWeekPart !== '*') {
|
|
86
|
+
type = 'weekly';
|
|
87
|
+
weekDays = parseWeekDays(dayOfWeekPart);
|
|
88
|
+
}
|
|
89
|
+
// Monthly: M H 1,15 * * (day-of-month specified)
|
|
90
|
+
else if (dayOfMonthPart !== '*' && monthPart === '*' && dayOfWeekPart === '*') {
|
|
91
|
+
type = 'monthly';
|
|
92
|
+
monthDays = parseMonthDays(dayOfMonthPart);
|
|
93
|
+
}
|
|
94
|
+
// Everything else is custom
|
|
95
|
+
|
|
96
|
+
return { type, weekDays, monthDays };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Parses a single numeric field
|
|
101
|
+
*/
|
|
102
|
+
function parseField(part: string, min: number, max: number): number | null {
|
|
103
|
+
// Handle simple number
|
|
104
|
+
if (/^\d+$/.test(part)) {
|
|
105
|
+
const num = parseInt(part, 10);
|
|
106
|
+
if (num >= min && num <= max) return num;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Parses week days from cron field
|
|
113
|
+
* Supports: 1,2,3 or 1-5 or MON,WED,FRI
|
|
114
|
+
*/
|
|
115
|
+
function parseWeekDays(part: string): WeekDay[] {
|
|
116
|
+
const result: WeekDay[] = [];
|
|
117
|
+
|
|
118
|
+
// Handle ranges like 1-5
|
|
119
|
+
if (part.includes('-')) {
|
|
120
|
+
const [start, end] = part.split('-').map(s => parseInt(s, 10));
|
|
121
|
+
if (!isNaN(start) && !isNaN(end)) {
|
|
122
|
+
for (let i = start; i <= end && i <= 6; i++) {
|
|
123
|
+
if (i >= 0) result.push(i as WeekDay);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return result.length > 0 ? result : [1, 2, 3, 4, 5];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Handle comma-separated list
|
|
130
|
+
for (const segment of part.split(',')) {
|
|
131
|
+
const num = parseInt(segment.trim(), 10);
|
|
132
|
+
if (!isNaN(num) && num >= 0 && num <= 6) {
|
|
133
|
+
result.push(num as WeekDay);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result.length > 0 ? result : [1, 2, 3, 4, 5];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Parses month days from cron field
|
|
142
|
+
* Supports: 1,15 or 1-15
|
|
143
|
+
*/
|
|
144
|
+
function parseMonthDays(part: string): MonthDay[] {
|
|
145
|
+
const result: MonthDay[] = [];
|
|
146
|
+
|
|
147
|
+
// Handle ranges like 1-15
|
|
148
|
+
if (part.includes('-')) {
|
|
149
|
+
const [start, end] = part.split('-').map(s => parseInt(s, 10));
|
|
150
|
+
if (!isNaN(start) && !isNaN(end)) {
|
|
151
|
+
for (let i = start; i <= end && i <= 31; i++) {
|
|
152
|
+
if (i >= 1) result.push(i as MonthDay);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return result.length > 0 ? result : [1];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Handle comma-separated list
|
|
159
|
+
for (const segment of part.split(',')) {
|
|
160
|
+
const num = parseInt(segment.trim(), 10);
|
|
161
|
+
if (!isNaN(num) && num >= 1 && num <= 31) {
|
|
162
|
+
result.push(num as MonthDay);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return result.length > 0 ? result : [1];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Validates cron expression syntax
|
|
171
|
+
*/
|
|
172
|
+
export function isValidCron(cron: string): boolean {
|
|
173
|
+
if (!cron || typeof cron !== 'string') return false;
|
|
174
|
+
|
|
175
|
+
const parts = cron.trim().split(/\s+/);
|
|
176
|
+
if (parts.length !== 5) return false;
|
|
177
|
+
|
|
178
|
+
// Basic validation for each field
|
|
179
|
+
const patterns = [
|
|
180
|
+
/^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // minute
|
|
181
|
+
/^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // hour
|
|
182
|
+
/^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // day of month
|
|
183
|
+
/^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // month
|
|
184
|
+
/^(\*|\d{1}|\d{1}-\d{1}|\d{1}(,\d{1})*|\*\/\d{1,2})$/, // day of week
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
return parts.every((part, i) => patterns[i].test(part));
|
|
188
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { buildCron, buildDefaultCron } from './cron-builder';
|
|
6
|
+
export { parseCron, isValidCron } from './cron-parser';
|
|
7
|
+
export {
|
|
8
|
+
humanizeCron,
|
|
9
|
+
formatTime12h,
|
|
10
|
+
getWeekdayName,
|
|
11
|
+
getWeekdayShort,
|
|
12
|
+
} from './cron-humanize';
|
package/src/tools/index.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - VideoPlayer: ~150KB (Professional video player with Vidstack)
|
|
12
12
|
* - AudioPlayer: ~200KB (Audio player with WaveSurfer.js)
|
|
13
13
|
* - ImageViewer: ~50KB (Image viewer with zoom/pan/rotate)
|
|
14
|
+
* - CronScheduler: ~15KB (Cron expression builder)
|
|
14
15
|
*
|
|
15
16
|
* Works in any React environment: Next.js, Vite, Wails, CRA
|
|
16
17
|
*/
|
|
@@ -161,6 +162,41 @@ export type {
|
|
|
161
162
|
export { ImageViewer } from './ImageViewer';
|
|
162
163
|
export type { ImageViewerProps, ImageFile } from './ImageViewer';
|
|
163
164
|
|
|
165
|
+
// Export CronScheduler (~15KB)
|
|
166
|
+
export {
|
|
167
|
+
CronScheduler,
|
|
168
|
+
// Context & Hooks
|
|
169
|
+
CronSchedulerProvider,
|
|
170
|
+
useCronSchedulerContext,
|
|
171
|
+
useCronType,
|
|
172
|
+
useCronTime,
|
|
173
|
+
useCronWeekDays,
|
|
174
|
+
useCronMonthDays,
|
|
175
|
+
useCronCustom,
|
|
176
|
+
useCronPreview,
|
|
177
|
+
useCronScheduler,
|
|
178
|
+
// Utilities
|
|
179
|
+
buildCron,
|
|
180
|
+
parseCron,
|
|
181
|
+
isValidCron,
|
|
182
|
+
humanizeCron,
|
|
183
|
+
// Components
|
|
184
|
+
ScheduleTypeSelector,
|
|
185
|
+
TimeSelector,
|
|
186
|
+
DayChips,
|
|
187
|
+
MonthDayGrid,
|
|
188
|
+
CustomInput,
|
|
189
|
+
SchedulePreview,
|
|
190
|
+
} from './CronScheduler';
|
|
191
|
+
export type {
|
|
192
|
+
CronSchedulerProps,
|
|
193
|
+
ScheduleType,
|
|
194
|
+
WeekDay,
|
|
195
|
+
MonthDay,
|
|
196
|
+
CronSchedulerState,
|
|
197
|
+
CronSchedulerContextValue,
|
|
198
|
+
} from './CronScheduler';
|
|
199
|
+
|
|
164
200
|
// Export Media Cache Store
|
|
165
201
|
export {
|
|
166
202
|
useMediaCacheStore,
|