@@ -26,6 +26,116 @@ import {isFlagEnabled} from 'src/shared/utils/featureFlag'
2626
2727import './style.scss'
2828
29+ const validCron = ( text : string ) : boolean => {
30+ const isNumber = ( str : string , min : number , max : number ) => {
31+ if ( str . search ( / [ ^ \d - , \/ * ] / ) !== - 1 ) {
32+ return false
33+ }
34+
35+ return str . split ( ',' ) . every ( item => {
36+ if ( item . trim ( ) . endsWith ( '/' ) ) {
37+ return false
38+ }
39+ const splits = item . split ( '/' )
40+
41+ if ( splits . length > 2 ) {
42+ return false
43+ }
44+
45+ const [ left , right ] = splits
46+ const sides = left . split ( '-' )
47+
48+ if (
49+ right !== undefined &&
50+ ( ! / ^ \d + $ / . test ( right ) || parseInt ( right ) <= 0 )
51+ ) {
52+ return false
53+ }
54+
55+ if ( sides . length > 2 ) {
56+ return false
57+ }
58+
59+ if ( sides . length === 1 ) {
60+ return (
61+ sides [ 0 ] === '*' ||
62+ ( / ^ \d + $ / . test ( sides [ 0 ] ) &&
63+ min <= parseInt ( sides [ 0 ] ) &&
64+ parseInt ( sides [ 0 ] ) <= max )
65+ )
66+ }
67+
68+ if ( ! / ^ \d + $ / . test ( sides [ 0 ] ) || ! / ^ \d + $ / . test ( sides [ 1 ] ) ) {
69+ return false
70+ }
71+
72+ const small = parseInt ( sides [ 0 ] )
73+ const big = parseInt ( sides [ 1 ] )
74+
75+ return (
76+ ! isNaN ( small ) &&
77+ ! isNaN ( big ) &&
78+ small <= big &&
79+ min <= small &&
80+ small <= max &&
81+ min <= big &&
82+ big <= max
83+ )
84+ } )
85+ }
86+
87+ const mapMonth = ( str : string ) : string =>
88+ str . toLowerCase ( ) . replace (
89+ / [ a - z ] { 3 } / g,
90+ _str =>
91+ ( {
92+ jan : '1' ,
93+ feb : '2' ,
94+ mar : '3' ,
95+ apr : '4' ,
96+ may : '5' ,
97+ jun : '6' ,
98+ jul : '7' ,
99+ aug : '8' ,
100+ sep : '9' ,
101+ oct : '10' ,
102+ nov : '11' ,
103+ dec : '12' ,
104+ } [ _str ] || _str )
105+ )
106+ const mapDay = ( str : string ) : string =>
107+ str . toLowerCase ( ) . replace (
108+ / [ a - z ] { 3 } / g,
109+ _str =>
110+ ( {
111+ sun : '0' ,
112+ mon : '1' ,
113+ tue : '2' ,
114+ wed : '3' ,
115+ thu : '4' ,
116+ fri : '5' ,
117+ sat : '6' ,
118+ } [ _str ] || _str )
119+ )
120+ const split = text . trim ( ) . split ( / \s + / )
121+ if ( split . length < 5 || split . length > 6 ) {
122+ return false
123+ }
124+
125+ if ( split . length === 5 ) {
126+ split . unshift ( '*' )
127+ }
128+
129+ return [
130+ isNumber ( split [ 0 ] , 0 , 59 ) ,
131+ isNumber ( split [ 1 ] , 0 , 59 ) ,
132+ isNumber ( split [ 2 ] , 0 , 23 ) ,
133+ isNumber ( split [ 3 ] , 1 , 31 ) ,
134+ isNumber ( mapMonth ( split [ 4 ] ) , 1 , 12 ) ,
135+ isNumber ( mapDay ( split [ 5 ] ) , 0 , 7 ) ,
136+ ] . reduce ( ( acc , curr ) => acc && curr , true )
137+ }
138+
29139const Schedule : FC < PipeProp > = ( { Context} ) => {
30140 const { id, data, update} = useContext ( PipeContext )
31141 const { simplify, getPanelQueries} = useContext ( FlowQueryContext )
@@ -37,7 +147,8 @@ const Schedule: FC<PipeProp> = ({Context}) => {
37147 intervalError = 'Required'
38148 } else if (
39149 data . interval !==
40- data . interval . match ( / (?: ( \d + ( y | m o | s | m | w | h ) { 1 } ) ) / g) ?. join ( '' )
150+ data . interval . match ( / (?: ( \d + ( y | m o | s | m | w | h ) { 1 } ) ) / g) ?. join ( '' ) &&
151+ ! validCron ( data . interval )
41152 ) {
42153 intervalError = 'Invalid Time'
43154 }
@@ -98,7 +209,11 @@ const Schedule: FC<PipeProp> = ({Context}) => {
98209 }
99210
100211 if ( data . interval && ! intervalError ) {
101- params . every = data . interval
212+ if ( validCron ( data . interval ) ) {
213+ params . cron = `"${ data . interval } "`
214+ } else {
215+ params . every = data . interval
216+ }
102217 }
103218
104219 if ( data . offset && ! offsetError ) {
@@ -221,6 +336,23 @@ const Schedule: FC<PipeProp> = ({Context}) => {
221336 < FlexBox . Child grow = { 1 } shrink = { 1 } style = { { alignSelf : 'start' } } >
222337 < Form . Element
223338 label = "Every"
339+ helpText = {
340+ ( (
341+ < >
342+ Supports{ ' ' }
343+ < a
344+ href = "https://docs.influxdata.com/flux/v0.x/data-types/basic/duration/#duration-syntax"
345+ target = "_blank"
346+ >
347+ flux durations
348+ </ a > { ' ' }
349+ and{ ' ' }
350+ < a href = "https://crontab.guru" target = "_blank" >
351+ cron intervals
352+ </ a >
353+ </ >
354+ ) as unknown ) as string
355+ }
224356 required = { true }
225357 errorMessage = { intervalError }
226358 >
@@ -241,6 +373,19 @@ const Schedule: FC<PipeProp> = ({Context}) => {
241373 < FlexBox . Child grow = { 1 } shrink = { 1 } style = { { alignSelf : 'start' } } >
242374 < Form . Element
243375 label = "Offset"
376+ helpText = {
377+ ( (
378+ < >
379+ Supports{ ' ' }
380+ < a
381+ href = "https://docs.influxdata.com/flux/v0.x/data-types/basic/duration/#duration-syntax"
382+ target = "_blank"
383+ >
384+ flux durations
385+ </ a >
386+ </ >
387+ ) as unknown ) as string
388+ }
244389 required = { false }
245390 errorMessage = { offsetError }
246391 >
0 commit comments