@@ -44,6 +44,12 @@ function LocationsSelect({ ariaLabel, locations, value, onChange }) {
44
44
) ;
45
45
}
46
46
47
+ export function DownloadImmutableFormInput ( { max, value, onChange } ) {
48
+ return (
49
+ < Form . Control type = "number" value = { value } onChange = { onChange } required min = { 0 } max = { max } />
50
+ ) ;
51
+ }
52
+
47
53
export default function DownloadButton ( { artifactUrl, ...props } ) {
48
54
const [ show , setShow ] = useState ( false ) ;
49
55
const target = useRef ( null ) ;
@@ -54,6 +60,7 @@ export default function DownloadButton({ artifactUrl, ...props }) {
54
60
const [ digestLocationIndex , setDigestLocationIndex ] = useState ( 0 ) ;
55
61
const [ immutableLocationIndex , setImmutableLocationIndex ] = useState ( 0 ) ;
56
62
const [ ancillaryLocationIndex , setAncillaryLocationIndex ] = useState ( 0 ) ;
63
+ const [ showImmutableDownloadValidation , setShowImmutableDownloadValidation ] = useState ( false ) ;
57
64
58
65
const handleClose = ( ) => setShow ( false ) ;
59
66
@@ -83,11 +90,20 @@ export default function DownloadButton({ artifactUrl, ...props }) {
83
90
window . open ( uri , "_blank" , "noopener" ) ;
84
91
}
85
92
86
- function downloadImmutable ( ) {
87
- const location = artifact ?. locations . immutables [ immutableLocationIndex ] ;
93
+ function downloadImmutable ( event ) {
94
+ // Prevent page refresh
95
+ event . preventDefault ( ) ;
96
+ const form = event . target ;
97
+
98
+ if ( form . checkValidity ( ) === true ) {
99
+ const location = artifact ?. locations . immutables [ immutableLocationIndex ] ;
88
100
89
- if ( location ?. type === "cloud_storage" ) {
90
- directDownload ( getImmutableUrlFromTemplate ( location . uri . Template , immutableFileNumber ) ) ;
101
+ if ( location ?. type === "cloud_storage" ) {
102
+ directDownload ( getImmutableUrlFromTemplate ( location . uri . Template , immutableFileNumber ) ) ;
103
+ }
104
+ setShowImmutableDownloadValidation ( false ) ;
105
+ } else {
106
+ setShowImmutableDownloadValidation ( true ) ;
91
107
}
92
108
}
93
109
@@ -141,22 +157,28 @@ export default function DownloadButton({ artifactUrl, ...props }) {
141
157
</ Alert >
142
158
143
159
< Form . Text > Immutable (max: { maxImmutableFileNumber } )</ Form . Text >
144
- < InputGroup >
145
- < Form . Control
146
- type = "text"
147
- value = { immutableFileNumber }
148
- onChange = { ( e ) => setImmutableFileNumber ( e . target . value ) }
149
- />
150
- < LocationsSelect
151
- ariaLabel = "Immutable locations"
152
- locations = { artifact ?. locations . immutables }
153
- onChange = { ( e ) => setImmutableLocationIndex ( e . target . value ) }
154
- value = { immutableLocationIndex }
155
- />
156
- < Button variant = "primary" onClick = { downloadImmutable } >
157
- < DownloadIcon />
158
- </ Button >
159
- </ InputGroup >
160
+ < Form
161
+ noValidate
162
+ onSubmit = { downloadImmutable }
163
+ validated = { showImmutableDownloadValidation } >
164
+ < InputGroup >
165
+ < DownloadImmutableFormInput
166
+ type = "text"
167
+ max = { maxImmutableFileNumber }
168
+ value = { immutableFileNumber }
169
+ onChange = { ( e ) => setImmutableFileNumber ( e . target . value ) }
170
+ />
171
+ < LocationsSelect
172
+ ariaLabel = "Immutable locations"
173
+ locations = { artifact ?. locations . immutables }
174
+ onChange = { ( e ) => setImmutableLocationIndex ( e . target . value ) }
175
+ value = { immutableLocationIndex }
176
+ />
177
+ < Button variant = "primary" type = "submit" >
178
+ < DownloadIcon />
179
+ </ Button >
180
+ </ InputGroup >
181
+ </ Form >
160
182
161
183
< Form . Text > Digests</ Form . Text >
162
184
< InputGroup >
0 commit comments