@@ -44,6 +44,7 @@ import {
44
44
RegistryType ,
45
45
EA_MODE_REGISTRY_TITLE_DESCRIPTION_CONTENT ,
46
46
URLS ,
47
+ PATTERNS ,
47
48
} from '../../config'
48
49
import Tippy from '@tippyjs/react'
49
50
import { ReactComponent as Dropdown } from '../../assets/icons/ic-chevron-down.svg'
@@ -64,6 +65,7 @@ import { ReactComponent as InfoIcon } from '../../assets/icons/info-filled.svg'
64
65
import { VALIDATION_STATUS , ValidateForm } from '../common/ValidateForm/ValidateForm'
65
66
import { ReactComponent as ErrorInfo } from '../../assets/icons/misc/errorInfo.svg'
66
67
import { ReactComponent as AlertTriangle } from '../../assets/icons/ic-alert-triangle.svg'
68
+ import { SwitchTransition } from 'react-transition-group'
67
69
68
70
const RegistryHelmPushCheckbox = importComponentFromFELibrary ( 'RegistryHelmPushCheckbox' )
69
71
@@ -322,18 +324,15 @@ function DockerForm({
322
324
} ,
323
325
...rest
324
326
} ) {
327
+ const re = PATTERNS . APP_NAME
328
+ const regExp = new RegExp ( re )
325
329
const { state, disable, handleOnChange, handleOnSubmit } = useForm (
326
330
{
327
- id : { value : id , error : '' } ,
328
331
registryType : { value : registryType || 'ecr' , error : '' } ,
329
332
advanceSelect : { value : connection || CERTTYPE . SECURE , error : '' } ,
330
333
certInput : { value : cert || '' , error : '' } ,
331
334
} ,
332
335
{
333
- id : {
334
- required : true ,
335
- validator : { error : 'Do not use "/" ' , regex : / ^ [ ^ / ] + $ / } ,
336
- } ,
337
336
registryType : {
338
337
required : true ,
339
338
validator : { error : 'Type is required' , regex : / ^ .* $ / } ,
@@ -361,6 +360,7 @@ function DockerForm({
361
360
: password
362
361
363
362
const [ customState , setCustomState ] = useState ( {
363
+ id : { value : id , error : '' } ,
364
364
awsAccessKeyId : { value : awsAccessKeyId , error : '' } ,
365
365
awsSecretAccessKey : {
366
366
value : id && ! awsSecretAccessKey ? DEFAULT_SECRET_PLACEHOLDER : awsSecretAccessKey ,
@@ -372,8 +372,29 @@ function DockerForm({
372
372
value : id && ! password ? DEFAULT_SECRET_PLACEHOLDER : regPass ,
373
373
error : '' ,
374
374
} ,
375
- repositoryList : { value : repositoryList . join ( ',' ) || '' , error : '' } ,
375
+ repositoryList : {
376
+ value : repositoryList . join ( ', ' ) || '' ,
377
+ error : '' ,
378
+ } ,
376
379
} )
380
+ const customStateValidator = {
381
+ id : [
382
+ { error : 'Name is required' , regex : / ^ (? = .* ) .{ 1 , } $ / } ,
383
+ {
384
+ error : "Start with alphabet; End with alphanumeric; Use only lowercase; Allowed:(-); Do not use 'spaces'" ,
385
+ regex : regExp ,
386
+ } ,
387
+ { error : 'Minimum 3 and Maximum 30 characters required' , regex : / ^ .{ 3 , 30 } $ / }
388
+ ] ,
389
+ registryUrl : [ { error : "Registry URL is required; Do not use 'spaces'" , regex : / ^ (? = .* ) .{ 1 , } $ / } ] ,
390
+ repositoryList : [
391
+ { error : "Registry List is required" , regex : / ^ (? = .* ) .{ 1 , } $ / } ,
392
+ { error : "Do not use 'spaces' or ',' at the start or at the end; new lines are not allowed" , regex : / ^ (? ! .* [ \s , ] $ ) (? ! ^ [ \s , ] ) .* ?(?< ! \s ) $ / } ,
393
+ { error : "Use only one 'space' after ','" , regex : / ^ (? ! .* , \s { 2 , } ) .* / } ,
394
+ { error : "Consecutive ',' are not allowed" , regex : / ^ (? ! .* , { 2 , } ) .* / } ,
395
+ { error : "Repository name cannot be empty and must be separated by ','" , regex : / ^ (? ! .* , \s { 1 , } , ) .* / }
396
+ ] ,
397
+ }
377
398
378
399
const clusterlistMap = new Map ( )
379
400
@@ -443,24 +464,36 @@ function DockerForm({
443
464
? `${ URLS . CHARTS_DISCOVER } ?registryId=${ id } `
444
465
: URLS . CHARTS_DISCOVER
445
466
446
- function customHandleChange ( e ) {
447
- setCustomState ( ( st ) => ( { ...st , [ e . target . name ] : { value : e . target . value , error : '' } } ) )
467
+ const customHandleChange = ( e ) : void => {
468
+ updateWithCustomStateValidation ( e . target . name , e . target . value )
469
+ }
470
+
471
+ const updateWithCustomStateValidation = ( name : string , value : any ) : Boolean => {
472
+ let errorMessage : string = ''
473
+ customStateValidator [ name ] ?. forEach ( ( validator ) => {
474
+ if ( ! validator . regex . test ( value ) ) {
475
+ errorMessage = validator . error
476
+ return
477
+ }
478
+ } )
479
+ setCustomState ( ( st ) => ( { ...st , [ name ] : { value, error : errorMessage } } ) )
480
+ return ! ! errorMessage
448
481
}
449
482
450
483
const handleRegistryTypeChange = ( selectedRegistry ) => {
451
484
setSelectedDockerRegistryType ( selectedRegistry )
452
485
setCustomState ( ( st ) => ( {
453
486
...st ,
454
- username : { value : selectedRegistry . id . defaultValue , error : '' } ,
455
487
registryUrl : { value : selectedRegistry . defaultRegistryURL , error : '' } ,
488
+ username : { value : selectedRegistry . id . defaultValue , error : '' } ,
489
+ password : { value : selectedRegistry . password . defaultValue , error : '' } ,
490
+ awsAccessKeyId : { value : "" , error : '' } ,
491
+ awsSecretAccessKey : { value : "" , error : '' } ,
456
492
} ) )
457
493
}
458
494
459
495
const handleRepositoryListChange = ( e ) => {
460
- setCustomState ( ( st ) => ( {
461
- ...st ,
462
- repositoryList : { value : e . target ?. value || '' , error : '' } ,
463
- } ) )
496
+ updateWithCustomStateValidation ( "repositoryList" , e . target . value )
464
497
}
465
498
466
499
const onECRAuthTypeChange = ( e ) => {
@@ -527,7 +560,7 @@ function DockerForm({
527
560
? { CHART : OCIRegistryConfigConstants . PULL }
528
561
: OCIRegistryStorageConfig
529
562
return {
530
- id : state . id . value ,
563
+ id : customState . id . value ,
531
564
pluginId : 'cd.go.artifact.docker.registry' ,
532
565
registryType : selectedDockerRegistryType . value ,
533
566
isDefault :
@@ -547,7 +580,10 @@ function DockerForm({
547
580
( registryStorageType === RegistryStorageType . OCI_PUBLIC ||
548
581
OCIRegistryStorageConfig ?. CHART === OCIRegistryConfigConstants . PULL_PUSH ||
549
582
OCIRegistryStorageConfig ?. CHART === OCIRegistryConfigConstants . PULL )
550
- ? customState . repositoryList ?. value . split ( ',' ) || [ ]
583
+ ? customState . repositoryList ?. value
584
+ . trim ( )
585
+ . replace ( ', ' , ',' )
586
+ . split ( ',' ) || [ ]
551
587
: null ,
552
588
registryUrl : customState . registryUrl . value
553
589
?. trim ( )
@@ -694,133 +730,115 @@ function DockerForm({
694
730
}
695
731
}
696
732
697
- function onValidation ( ) {
698
- if ( selectedDockerRegistryType . value === RegistryType . ECR ) {
699
- if ( registryStorageType === RegistryStorageType . OCI_PRIVATE &&
700
- ( ! isIAMAuthType &&
701
- ( ! customState . awsAccessKeyId . value || ! ( customState . awsSecretAccessKey . value || id ) ) ) ||
702
- ! customState . registryUrl . value
703
- ) {
704
- setCustomState ( ( st ) => ( {
705
- ...st ,
706
- awsAccessKeyId : { ...st . awsAccessKeyId , error : st . awsAccessKeyId . value ? '' : 'Mandatory' } ,
707
- awsSecretAccessKey : {
708
- ...st . awsSecretAccessKey ,
709
- error : id || st . awsSecretAccessKey . value ? '' : 'Mandatory' ,
710
- } ,
711
- registryUrl : { ...st . registryUrl , error : st . registryUrl . value ? '' : 'Mandatory' } ,
712
- } ) )
713
- return
714
- }
715
- if ( ! customState . registryUrl . value ) {
716
- setCustomState ( ( st ) => ( {
717
- ...st ,
718
- registryUrl : { ...st . registryUrl , error : st . registryUrl . value ? '' : 'Mandatory' } ,
719
- } ) )
720
- return
721
- }
722
- } else if ( selectedDockerRegistryType . value === RegistryType . DOCKER_HUB ) {
723
- if (
724
- registryStorageType === RegistryStorageType . OCI_PRIVATE &&
725
- ( ! customState . username . value || ! ( customState . password . value || id ) )
726
- ) {
727
- setCustomState ( ( st ) => ( {
728
- ...st ,
729
- username : { ...st . username , error : st . username . value ? '' : 'Mandatory' } ,
730
- password : { ...st . password , error : id || st . password . value ? '' : 'Mandatory' } ,
731
- } ) )
732
- return
733
- }
734
- if ( ! customState . registryUrl . value ) {
735
- setCustomState ( ( st ) => ( {
736
- ...st ,
737
- registryUrl : { ...st . registryUrl , error : st . registryUrl . value ? '' : 'Mandatory' } ,
738
- } ) )
739
- return
740
- }
741
- } else if (
742
- selectedDockerRegistryType . value === RegistryType . ARTIFACT_REGISTRY ||
743
- selectedDockerRegistryType . value === RegistryType . GCR
744
- ) {
745
- const isValidJsonFile = isValidJson ( customState . password . value ) || id
746
- const isValidJsonStr = isValidJsonFile ? '' : 'Invalid JSON'
747
- if (
748
- registryStorageType === RegistryStorageType . OCI_PRIVATE &&
749
- ( ! customState . username . value || ! ( customState . password . value || id ) || ! isValidJsonFile )
750
- ) {
751
- setCustomState ( ( st ) => ( {
752
- ...st ,
753
- username : { ...st . username , error : st . username . value ? '' : 'Mandatory' } ,
754
- password : {
755
- ...st . password ,
756
- error : id || st . password . value ? isValidJsonStr : 'Mandatory' ,
757
- } ,
758
- registryUrl : { ...st . registryUrl , error : st . registryUrl . value ? '' : 'Mandatory' } ,
759
- } ) )
760
- return
761
- }
762
- if ( ! customState . registryUrl . value ) {
763
- setCustomState ( ( st ) => ( {
764
- ...st ,
765
- registryUrl : { ...st . registryUrl , error : st . registryUrl . value ? '' : 'Mandatory' } ,
766
- } ) )
767
- return
768
- }
769
- } else if (
770
- selectedDockerRegistryType . value === RegistryType . ACR ||
771
- selectedDockerRegistryType . value === RegistryType . QUAY ||
772
- selectedDockerRegistryType . value === RegistryType . OTHER
773
- ) {
774
- let error = false
775
- if ( registryStorageType !== RegistryStorageType . OCI_PUBLIC ) {
733
+ function onValidation ( ) {
734
+ // Custom state validation for Registry Id
735
+ if ( ! id && updateWithCustomStateValidation ( "id" , customState . id . value ) ) {
736
+ return
737
+ } else if ( ! customState . id . value ) {
738
+ setCustomState ( ( st ) => ( {
739
+ ...st ,
740
+ id : { ...st . id , error : 'Name is required' } ,
741
+ } ) )
742
+ return
743
+ } else if ( customState . id . value . includes ( "/" ) ) {
744
+ setCustomState ( ( st ) => ( {
745
+ ...st ,
746
+ id : { ...st . id , error : 'Do not use "/"' } ,
747
+ } ) )
748
+ return
749
+ }
750
+
751
+ // Custom state validation for Registry URL
752
+ if ( updateWithCustomStateValidation ( "registryUrl" , customState . registryUrl . value ) ) {
753
+ return
754
+ }
755
+ switch ( selectedDockerRegistryType . value ) {
756
+ case RegistryType . ECR :
757
+ if ( registryStorageType === RegistryStorageType . OCI_PRIVATE &&
758
+ ( ! isIAMAuthType &&
759
+ ( ! customState . awsAccessKeyId . value || ! ( customState . awsSecretAccessKey . value || id ) ) )
760
+ ) {
761
+ setCustomState ( ( st ) => ( {
762
+ ...st ,
763
+ awsAccessKeyId : { ...st . awsAccessKeyId , error : st . awsAccessKeyId . value ? '' : 'Mandatory' } ,
764
+ awsSecretAccessKey : {
765
+ ...st . awsSecretAccessKey ,
766
+ error : id || st . awsSecretAccessKey . value ? '' : 'Mandatory' ,
767
+ } ,
768
+ } ) )
769
+ return
770
+ }
771
+ break ;
772
+ case RegistryType . DOCKER_HUB :
776
773
if (
777
- ! customState . username . value ||
778
- ! ( customState . password . value || id ) ||
779
- ! customState . registryUrl . value
774
+ registryStorageType === RegistryStorageType . OCI_PRIVATE &&
775
+ ( ! customState . username . value || ! ( customState . password . value || id ) )
780
776
) {
781
777
setCustomState ( ( st ) => ( {
782
778
...st ,
783
779
username : { ...st . username , error : st . username . value ? '' : 'Mandatory' } ,
784
780
password : { ...st . password , error : id || st . password . value ? '' : 'Mandatory' } ,
785
- registryUrl : { ...st . registryUrl , error : st . registryUrl . value ? '' : 'Mandatory' } ,
786
781
} ) )
787
- error = true
782
+ return
783
+ }
784
+ break
785
+ case RegistryType . ARTIFACT_REGISTRY :
786
+ case RegistryType . GCR :
787
+ const isValidJsonFile = isValidJson ( customState . password . value ) || id
788
+ const isValidJsonStr = isValidJsonFile ? '' : 'Invalid JSON'
789
+ if (
790
+ registryStorageType === RegistryStorageType . OCI_PRIVATE &&
791
+ ( ! customState . username . value || ! ( customState . password . value || id ) || ! isValidJsonFile )
792
+ ) {
793
+ setCustomState ( ( st ) => ( {
794
+ ...st ,
795
+ username : { ...st . username , error : st . username . value ? '' : 'Mandatory' } ,
796
+ password : {
797
+ ...st . password ,
798
+ error : id || st . password . value ? isValidJsonStr : 'Mandatory' ,
799
+ } ,
800
+ } ) )
801
+ return
788
802
}
789
- } else {
790
- if ( ! customState . registryUrl . value ) {
803
+ break
804
+ case RegistryType . ACR :
805
+ case RegistryType . QUAY :
806
+ case RegistryType . OTHER :
807
+ let error = false
808
+ if (
809
+ registryStorageType === RegistryStorageType . OCI_PRIVATE &&
810
+ ( ! customState . username . value || ! ( customState . password . value || id ) )
811
+ ) {
791
812
setCustomState ( ( st ) => ( {
792
813
...st ,
793
- registryUrl : { ...st . registryUrl , error : st . registryUrl . value ? '' : 'Mandatory' } ,
814
+ username : { ...st . username , error : st . username . value ? '' : 'Mandatory' } ,
815
+ password : { ...st . password , error : id || st . password . value ? '' : 'Mandatory' } ,
794
816
} ) )
795
817
error = true
796
818
}
797
- }
798
819
799
- if (
800
- selectedDockerRegistryType . value === RegistryType . OTHER &&
801
- state . advanceSelect . value === CERTTYPE . SECURE_WITH_CERT
802
- ) {
803
- if ( state . certInput . value === '' ) {
804
- if ( ! toggleCollapsedAdvancedRegistry ) {
805
- setToggleCollapsedAdvancedRegistry ( not )
820
+ if (
821
+ selectedDockerRegistryType . value === RegistryType . OTHER &&
822
+ state . advanceSelect . value === CERTTYPE . SECURE_WITH_CERT
823
+ ) {
824
+ if ( state . certInput . value === '' ) {
825
+ if ( ! toggleCollapsedAdvancedRegistry ) {
826
+ setToggleCollapsedAdvancedRegistry ( not )
827
+ }
828
+ setCertInputError ( 'Mandatory' )
829
+ error = true
830
+ } else {
831
+ setCertInputError ( '' )
806
832
}
807
- setCertInputError ( 'Mandatory' )
808
- error = true
809
- } else {
810
- setCertInputError ( '' )
811
833
}
812
- }
813
- if ( error ) {
814
- return
815
- }
834
+ if ( error ) {
835
+ return
836
+ }
837
+ break
816
838
}
817
839
if ( selectedDockerRegistryType . value !== RegistryType . GCR ) {
818
840
if ( showHelmPull || registryStorageType === RegistryStorageType . OCI_PUBLIC ) {
819
- setCustomState ( ( st ) => ( {
820
- ...st ,
821
- repositoryList : { ...st . repositoryList , error : st . repositoryList ?. value ? '' : 'Mandatory' } ,
822
- } ) )
823
- if ( customState . repositoryList ?. value === '' ) {
841
+ if ( updateWithCustomStateValidation ( "repositoryList" , customState . repositoryList . value ) ) {
824
842
return
825
843
}
826
844
}
@@ -1236,7 +1254,7 @@ function DockerForm({
1236
1254
className = "form__textarea"
1237
1255
name = "repositoryList"
1238
1256
autoFocus = { true }
1239
- value = { customState . repositoryList ?. value . trim ( ) }
1257
+ value = { customState . repositoryList ?. value }
1240
1258
autoComplete = "off"
1241
1259
tabIndex = { 3 }
1242
1260
onChange = { handleRepositoryListChange }
@@ -1630,11 +1648,11 @@ function DockerForm({
1630
1648
labelClassName = "dc__required-field"
1631
1649
name = "id"
1632
1650
autoFocus = { true }
1633
- value = { state . id . value }
1651
+ value = { customState . id . value }
1634
1652
autoComplete = "off"
1635
- error = { state . id . error }
1653
+ error = { customState . id . error }
1636
1654
tabIndex = { 1 }
1637
- onChange = { handleOnChange }
1655
+ onChange = { customHandleChange }
1638
1656
label = "Name"
1639
1657
disabled = { ! ! id }
1640
1658
placeholder = "e.g. Registry name"
0 commit comments