Copilot commented on code in PR #13204:
URL: https://github.com/apache/cloudstack/pull/13204#discussion_r3278989504
##########
ui/public/locales/en.json:
##########
@@ -3667,6 +3669,9 @@
"message.upload.iso.failed.description": "Failed to upload ISO.",
"message.upload.template.failed.description": "Failed to upload Template",
"message.upload.volume.failed": "Volume upload failed",
+"message.ssvm.cert.untrusted": "The upload server certificate is not trusted
by your browser.",
+"message.ssvm.cert.trust.instructions": "Click 'Open Certificate Page' to open
the upload server in a new browser tab. Accept the certificate warning shown by
your browser, then come back here and click 'Retry Upload'.",
+"message.ssvm.cert.still.untrusted": "The certificate still appears untrusted.
Please accept it in the opened tab and try again.",
Review Comment:
The new SSVM warning text asserts the failure is due to an “untrusted
certificate”, but `probeSsvmCert()` treats any network error (DNS failure,
routing/firewall, port closed, mixed-content blocking, etc.) the same as a TLS
trust error. Consider wording these messages more generically (e.g. “Unable to
reach upload server; if using a self-signed/expired certificate, open it in a
new tab to trust it”) so users aren’t misled.
##########
ui/src/views/storage/UploadLocalVolume.vue:
##########
@@ -267,6 +286,70 @@ export default {
this.form.account = accountName
this.account = accountName
},
+ async probeSsvmCert (origin) {
+ try {
+ await fetch(origin, { method: 'HEAD', mode: 'no-cors' })
+ return true
+ } catch (e) {
+ return false
+ }
+ },
+ async retryUpload () {
+ this.loading = true
+ const trusted = await this.probeSsvmCert(this.ssvmOrigin)
+ this.loading = false
+ if (!trusted) {
+ this.$message.warning(this.$t('message.ssvm.cert.still.untrusted'))
+ return
+ }
+ this.ssvmCertUntrusted = false
+ this.handleUpload()
+ },
+ handleUpload () {
+ const { fileList } = this
+ if (this.fileList.length > 1) {
+ this.$notification.error({
+ message: this.$t('message.upload.volume.failed'),
+ description: this.$t('message.upload.file.limit'),
+ duration: 0
+ })
Review Comment:
`handleUpload()` shows an error when more than one file is selected, but
then continues and posts all files anyway. This can lead to unexpected uploads
or server-side failures; after notifying, return early (or trim `fileList` to a
single file) to enforce the UI’s single-file contract.
##########
ui/src/views/image/RegisterOrUploadTemplate.vue:
##########
@@ -610,12 +628,32 @@ export default {
this.form.file = file
return false
},
+ async probeSsvmCert (origin) {
+ try {
+ await fetch(origin, { method: 'HEAD', mode: 'no-cors' })
+ return true
+ } catch (e) {
+ return false
+ }
+ },
+ async retryUpload () {
+ this.loading = true
+ const trusted = await this.probeSsvmCert(this.ssvmOrigin)
+ this.loading = false
+ if (!trusted) {
+ this.$message.warning(this.$t('message.ssvm.cert.still.untrusted'))
+ return
+ }
+ this.ssvmCertUntrusted = false
+ this.handleUpload()
+ },
Review Comment:
The SSVM probe / retry logic is duplicated across multiple upload components
(template/ISO/volume). To reduce the risk of behavioral drift and make future
changes (timeouts, messaging, additional checks) easier, consider extracting
this into a shared mixin/composable or a small utility module used by each
component.
##########
ui/src/views/storage/UploadLocalVolume.vue:
##########
@@ -267,6 +286,70 @@ export default {
this.form.account = accountName
this.account = accountName
},
+ async probeSsvmCert (origin) {
+ try {
+ await fetch(origin, { method: 'HEAD', mode: 'no-cors' })
+ return true
+ } catch (e) {
+ return false
Review Comment:
`probeSsvmCert()` has no timeout/abort, so if the SSVM IP/port is reachable
but the connection hangs, the UI can remain stuck in the loading state for an
extended period. Consider using an `AbortController` with a short timeout (e.g.
a few seconds) and treating abort as “untrusted/unreachable”.
##########
ui/src/views/image/RegisterOrUploadTemplate.vue:
##########
@@ -610,12 +628,32 @@ export default {
this.form.file = file
return false
},
+ async probeSsvmCert (origin) {
+ try {
+ await fetch(origin, { method: 'HEAD', mode: 'no-cors' })
+ return true
+ } catch (e) {
+ return false
Review Comment:
`probeSsvmCert()` has no timeout/abort, so if the SSVM IP/port is reachable
but the connection hangs, the UI can remain stuck in the loading state for an
extended period. Consider using an `AbortController` with a short timeout (e.g.
a few seconds) and treating abort as “untrusted/unreachable”.
##########
ui/src/views/image/RegisterOrUploadIso.vue:
##########
@@ -489,6 +508,25 @@ export default {
this.form.file = file
return false
},
+ async probeSsvmCert (origin) {
+ try {
+ await fetch(origin, { method: 'HEAD', mode: 'no-cors' })
+ return true
+ } catch (e) {
+ return false
Review Comment:
`probeSsvmCert()` has no timeout/abort, so if the SSVM IP/port is reachable
but the connection hangs, the UI can remain stuck in the loading state for an
extended period. Consider using an `AbortController` with a short timeout (e.g.
a few seconds) and treating abort as “untrusted/unreachable”.
##########
ui/src/views/storage/UploadLocalVolume.vue:
##########
@@ -17,11 +17,27 @@
<template>
<div class="form-layout" v-ctrl-enter="handleSubmit">
- <span v-if="uploadPercentage > 0">
+ <span v-if="uploading">
<loading-outlined />
{{ $t('message.upload.file.processing') }}
<a-progress :percent="uploadPercentage" />
</span>
Review Comment:
`v-ctrl-enter` is bound on the outer container, but when `ssvmCertUntrusted`
is true the form (and its `ref="submit"`) is not rendered. The `ctrlEnter`
directive’s keydown handler unconditionally calls
`vm.$refs.submit.$el.focus()`, which can throw when `$refs.submit` is
undefined. Consider moving `v-ctrl-enter` onto an element that is only rendered
with the form, or guarding against missing `submit` refs.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]