|
2 | 2 | import { env } from '$env/dynamic/public'; |
3 | 3 | import { onDestroy, onMount } from 'svelte'; |
4 | 4 | import TaskGroupActivityLogsModal from '$lib/components/v2/tasks/TaskGroupActivityLogsModal.svelte'; |
5 | | - import { replaceEmptyStrings } from '$lib/common/component_utilities'; |
6 | 5 | import { FormErrorHandler } from '$lib/common/errors'; |
7 | 6 | import TaskGroupSelector from './TaskGroupSelector.svelte'; |
8 | 7 | import { |
|
34 | 33 | let pinnedPackageVersions = []; |
35 | 34 | let privateTask = false; |
36 | 35 | let selectedGroup = null; |
| 36 | +
|
| 37 | + /** @type {FileList|null} */ |
| 38 | + let wheelFiles = null; |
| 39 | + /** @type {HTMLInputElement|undefined} */ |
| 40 | + let wheelFileInput = undefined; |
| 41 | +
|
37 | 42 | /** @type {TaskGroupActivityLogsModal} */ |
38 | 43 | let taskGroupActivitiesLogsModal; |
39 | 44 | /** @type {number|null} */ |
|
98 | 103 | async function handleTaskCollection() { |
99 | 104 | formErrorHandler.clearErrors(); |
100 | 105 |
|
101 | | - const headers = new Headers(); |
102 | | - headers.append('Content-Type', 'application/json'); |
| 106 | + if (packageType === 'local' && (wheelFiles === null || wheelFiles.length === 0)) { |
| 107 | + formErrorHandler.addValidationError('file', 'Required field'); |
| 108 | + return; |
| 109 | + } |
103 | 110 |
|
104 | | - const requestData = { |
105 | | - package: python_package, |
106 | | - python_version, |
107 | | - package_extras |
108 | | - }; |
| 111 | + const formData = new FormData(); |
109 | 112 |
|
110 | 113 | if (packageType === 'pypi') { |
111 | | - requestData.package_version = package_version; |
| 114 | + formData.append('package', python_package); |
| 115 | + } else if (wheelFiles?.length === 1) { |
| 116 | + formData.append('file', wheelFiles[0]); |
| 117 | + } |
| 118 | +
|
| 119 | + if (python_version) { |
| 120 | + formData.append('python_version', python_version); |
| 121 | + } |
| 122 | +
|
| 123 | + if (package_extras) { |
| 124 | + formData.append('package_extras', package_extras); |
| 125 | + } |
| 126 | +
|
| 127 | + if (packageType === 'pypi' && package_version) { |
| 128 | + formData.append('package_version', package_version); |
112 | 129 | } |
113 | 130 |
|
114 | 131 | const ppv = getPinnedPackageVersionsMap(); |
115 | 132 | if (ppv) { |
116 | | - requestData.pinned_package_versions = ppv; |
| 133 | + formData.append('pinned_package_versions', JSON.stringify(ppv)); |
117 | 134 | } |
118 | 135 |
|
119 | 136 | let url = `/api/v2/task/collect/pip?private=${privateTask}`; |
|
125 | 142 | const response = await fetch(url, { |
126 | 143 | method: 'POST', |
127 | 144 | credentials: 'include', |
128 | | - headers: headers, |
129 | | - body: JSON.stringify(requestData, replaceEmptyStrings) |
| 145 | + body: formData |
130 | 146 | }); |
| 147 | +
|
131 | 148 | taskCollectionInProgress = false; |
132 | 149 |
|
133 | 150 | if (response.ok) { |
|
140 | 157 | python_version = ''; |
141 | 158 | package_extras = ''; |
142 | 159 | pinnedPackageVersions = []; |
| 160 | + clearWheelFileUpload(); |
143 | 161 | } else { |
144 | 162 | console.error('Task collection request failed'); |
145 | 163 | await formErrorHandler.handleErrorResponse(response); |
|
216 | 234 | ); |
217 | 235 | } |
218 | 236 |
|
| 237 | + function clearWheelFileUpload() { |
| 238 | + wheelFiles = null; |
| 239 | + if (wheelFileInput) { |
| 240 | + wheelFileInput.value = ''; |
| 241 | + } |
| 242 | + formErrorHandler.removeValidationError('file'); |
| 243 | + } |
| 244 | +
|
219 | 245 | onDestroy(() => { |
220 | 246 | clearTimeout(updateTasksCollectionTimeout); |
221 | 247 | }); |
|
226 | 252 | <div> |
227 | 253 | <form on:submit|preventDefault={handleTaskCollection}> |
228 | 254 | <div class="row"> |
229 | | - <div |
230 | | - class="mb-2" |
231 | | - class:col-md-6={packageType === 'pypi'} |
232 | | - class:col-md-12={packageType === 'local'} |
233 | | - > |
234 | | - <div class="input-group has-validation"> |
235 | | - <div class="input-group-text"> |
236 | | - <label class="font-monospace" for="package">Package</label> |
| 255 | + {#if packageType === 'pypi'} |
| 256 | + <div class="mb-2 col-md-6"> |
| 257 | + <div class="input-group has-validation"> |
| 258 | + <div class="input-group-text"> |
| 259 | + <label class="font-monospace" for="package">Package</label> |
| 260 | + </div> |
| 261 | + <input |
| 262 | + name="package" |
| 263 | + id="package" |
| 264 | + type="text" |
| 265 | + class="form-control" |
| 266 | + required |
| 267 | + class:is-invalid={$validationErrors['package']} |
| 268 | + bind:value={python_package} |
| 269 | + /> |
| 270 | + <span class="invalid-feedback">{$validationErrors['package']}</span> |
237 | 271 | </div> |
238 | | - <input |
239 | | - name="package" |
240 | | - id="package" |
241 | | - type="text" |
242 | | - class="form-control" |
243 | | - required |
244 | | - class:is-invalid={$validationErrors['package']} |
245 | | - bind:value={python_package} |
246 | | - /> |
247 | | - <span class="invalid-feedback">{$validationErrors['package']}</span> |
| 272 | + <div class="form-text">The name of a package published on PyPI</div> |
248 | 273 | </div> |
249 | | - <div class="form-text"> |
250 | | - {#if packageType === 'pypi'} |
251 | | - The name of a package published on PyPI |
252 | | - {:else} |
253 | | - The full path to a wheel file |
254 | | - {/if} |
| 274 | + {:else if packageType === 'local'} |
| 275 | + <div class="mb-2 col-md-6"> |
| 276 | + <div class="input-group has-validation"> |
| 277 | + <label for="wheelFile" class="input-group-text"> |
| 278 | + <i class="bi bi-file-earmark-arrow-up" /> Upload a wheel file |
| 279 | + </label> |
| 280 | + <input |
| 281 | + class="form-control" |
| 282 | + accept=".whl" |
| 283 | + type="file" |
| 284 | + name="wheelFile" |
| 285 | + id="wheelFile" |
| 286 | + bind:this={wheelFileInput} |
| 287 | + bind:files={wheelFiles} |
| 288 | + class:is-invalid={$validationErrors['file']} |
| 289 | + /> |
| 290 | + {#if wheelFiles && wheelFiles.length > 0} |
| 291 | + <button class="btn btn-outline-secondary" on:click={clearWheelFileUpload}> |
| 292 | + Clear |
| 293 | + </button> |
| 294 | + {/if} |
| 295 | + <span class="invalid-feedback">{$validationErrors['file']}</span> |
| 296 | + </div> |
255 | 297 | </div> |
256 | | - </div> |
| 298 | + {/if} |
257 | 299 | {#if packageType === 'pypi'} |
258 | 300 | <div class="col-md-6 mb-2"> |
259 | 301 | <div class="input-group has-validation"> |
|
0 commit comments