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]

Reply via email to