Idempotent tunnel create: reuse existing, block UI double-submit
CI / test (push) Successful in 10m5s
CI / test (push) Successful in 10m5s
Return the active tunnel for the same host:port:protocol instead of starting a second Holesail instance; coalesce concurrent creates. UI disables the create button and shows “already exists” feedback.
This commit is contained in:
+28
-4
@@ -621,18 +621,29 @@ export async function loadTunnelsView(opts = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prevent double-submit while a create is in flight */
|
||||
let tunnelCreateBusy = false
|
||||
|
||||
export async function createTunnelFromForm() {
|
||||
const name = document.getElementById('tunnel-name')?.value?.trim()
|
||||
const host = document.getElementById('tunnel-host')?.value?.trim() || '127.0.0.1'
|
||||
const port = Number(document.getElementById('tunnel-port')?.value)
|
||||
const protocol = document.getElementById('tunnel-protocol')?.value || 'tcp'
|
||||
const secure = document.getElementById('tunnel-secure')?.checked !== false
|
||||
const btn = document.getElementById('tunnel-create-btn')
|
||||
if (!port || port < 1 || port > 65535) {
|
||||
showAlert('warning', 'Enter a valid port (1–65535)')
|
||||
return
|
||||
}
|
||||
if (tunnelCreateBusy) {
|
||||
showAlert('info', 'Tunnel create already in progress…')
|
||||
return
|
||||
}
|
||||
tunnelCreateBusy = true
|
||||
if (btn) btn.disabled = true
|
||||
try {
|
||||
let createdUrl = ''
|
||||
let wasExisting = false
|
||||
const job = await runJob(`Tunnel ${host}:${port}`, [
|
||||
{
|
||||
id: 'create',
|
||||
@@ -647,6 +658,8 @@ export async function createTunnelFromForm() {
|
||||
secure,
|
||||
})
|
||||
const url = res?.tunnel?.url
|
||||
wasExisting = Boolean(res?.existing)
|
||||
if (wasExisting) log('Tunnel already active — reusing existing hs:// URL')
|
||||
if (url) {
|
||||
createdUrl = url
|
||||
log(`URL: ${url}`)
|
||||
@@ -656,20 +669,31 @@ export async function createTunnelFromForm() {
|
||||
},
|
||||
])
|
||||
showJob(job)
|
||||
markFeedbackShown('success', `Tunnel created for ${host}:${port}`)
|
||||
const label = wasExisting
|
||||
? `Tunnel already exists for ${host}:${port}`
|
||||
: `Tunnel created for ${host}:${port}`
|
||||
markFeedbackShown(wasExisting ? 'info' : 'success', label)
|
||||
if (createdUrl && navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(createdUrl)
|
||||
showAlert('success', 'Tunnel created — hs:// URL copied')
|
||||
showAlert(
|
||||
wasExisting ? 'info' : 'success',
|
||||
wasExisting
|
||||
? 'Tunnel already exists — hs:// URL copied'
|
||||
: 'Tunnel created — hs:// URL copied'
|
||||
)
|
||||
} catch {
|
||||
showAlert('success', 'Tunnel created')
|
||||
showAlert(wasExisting ? 'info' : 'success', label)
|
||||
}
|
||||
} else {
|
||||
showAlert('success', 'Tunnel created')
|
||||
showAlert(wasExisting ? 'info' : 'success', label)
|
||||
}
|
||||
await loadTunnelsView()
|
||||
} catch (err) {
|
||||
if (!err?.viaJob) presentError(err, 'createTunnel', { showAlert })
|
||||
} finally {
|
||||
tunnelCreateBusy = false
|
||||
if (btn) btn.disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user