diff --git a/web/superball.html b/web/superball.html index fa93f82..65b827a 100644 --- a/web/superball.html +++ b/web/superball.html @@ -830,6 +830,35 @@ input.value = ''; clearRelayDropdown(bounceId); } + + // Check if bounce inputs are valid and update button state + updateCreateBounceButtonState(bounceId); + } + + // Check if bounce is ready to be created and update button state + function updateCreateBounceButtonState(bounceId) { + const button = document.getElementById(`create-bounce-btn-${bounceId}`); + if (!button) return; + + const throwerPubkey = getThrowerPubkeyForBounce(bounceId); + const relayInput = document.getElementById(`bounce-relays-${bounceId}`); + const hasRelays = relayInput && relayInput.value.trim().length > 0; + + const isValid = throwerPubkey && hasRelays; + + if (isValid) { + // Enable button + button.disabled = false; + button.style.color = ''; + button.style.borderColor = ''; + button.style.cursor = ''; + } else { + // Disable button + button.disabled = true; + button.style.color = 'var(--muted-color)'; + button.style.borderColor = 'var(--muted-color)'; + button.style.cursor = 'not-allowed'; + } } // Handle manual thrower pubkey input @@ -866,6 +895,9 @@ } else { clearRelayDropdown(bounceId); } + + // Update button state after thrower input change + updateCreateBounceButtonState(bounceId); } // Get thrower pubkey for a bounce (from dropdown or manual input) @@ -1022,6 +1054,9 @@ manualDiv.classList.add('hidden'); input.value = ''; } + + // Update button state after relay selection change + updateCreateBounceButtonState(bounceId); } // Handle manual relay input @@ -1036,6 +1071,9 @@ } console.log('INFO', `Manual relay input for bounce ${bounceId}: ${input.value}`); } + + // Update button state after manual relay input change + updateCreateBounceButtonState(bounceId); } // Get all writable relays for a thrower as comma-separated string @@ -1172,7 +1210,7 @@ - +
@@ -1623,7 +1661,9 @@ // For the first bounce, we skip the user publishing step since it's handled by the button // Start directly with relay propagation after the button click const routingEventSize = JSON.stringify(bounce.routingEvent).length; - const relays = getRelaysForBounce(bounceNumber); + + // Get the relays from the current bounce's routing instructions (where user publishes to) + const relays = bounce.payload?.routing?.relays || []; // Step 1: Relay propagates (immediate after button click) currentTime += 2000; // 2 seconds for relay propagation @@ -1645,7 +1685,10 @@ if (isLast) { // Last bounce - posts final event const finalEventSize = JSON.stringify(finalEvent).length + paddingAdjustment; - const finalRelays = getRelaysForBounce(bounceNumber); + + // Get the relays from the current bounce's routing instructions (where final event gets posted) + const finalRelays = bounce.payload?.routing?.relays || []; + const delaySeconds = getDelayForBounce(bounceNumber); const paddingAdded = getPaddingAdjustmentForBounce(bounceNumber); @@ -1673,38 +1716,43 @@ size: Math.max(finalEventSize, 0) }); } else { - // Intermediate bounce - forwards to next superball - const nextBounce = bounces[index + 1]; - const nextThrowerName = getThrowerName(nextBounce, bounceNumber + 1); - const nextRoutingSize = JSON.stringify(nextBounce.routingEvent).length + paddingAdjustment; - const nextRelays = getRelaysForBounce(bounceNumber + 1); // Next superball's relays - const delaySeconds = getDelayForBounce(bounceNumber); - const paddingAdded = getPaddingAdjustmentForBounce(bounceNumber); + // Intermediate bounce - forwards to next superball + const nextBounce = reversedBounces[index + 1]; + const nextBounceNumber = bounces.length - (index + 1); + const nextThrowerName = getThrowerName(nextBounce, nextBounceNumber); + const nextRoutingSize = JSON.stringify(nextBounce.routingEvent).length + paddingAdjustment; + + // Get the relays from the current bounce's routing instructions (where this thrower forwards to) + const currentBounce = reversedBounces[index]; + const forwardingRelays = currentBounce.payload?.routing?.relays || []; + + const delaySeconds = getDelayForBounce(bounceNumber); + const paddingAdded = getPaddingAdjustmentForBounce(bounceNumber); - // Create detailed forwarding action description - let actionDescription = `Grabs message, waits ${delaySeconds} seconds`; - if (paddingAdded > 0) { - actionDescription += `, adds ${paddingAdded} bytes of padding`; - } - actionDescription += `, and forwards to: ${nextRelays.join(', ')}`; + // Create detailed forwarding action description + let actionDescription = `Grabs message, waits ${delaySeconds} seconds`; + if (paddingAdded > 0) { + actionDescription += `, adds ${paddingAdded} bytes of padding`; + } + actionDescription += `, and forwards to: ${forwardingRelays.join(', ')}`; - // Step 3: Superball forwards to next relay - flow.push({ - time: currentTime, - actor: throwerName, - action: actionDescription, - size: Math.max(nextRoutingSize, 0) - }); + // Step 3: Superball forwards to next relay + flow.push({ + time: currentTime, + actor: throwerName, + action: actionDescription, + size: Math.max(nextRoutingSize, 0) + }); - // Step 4: Relay propagates to next superball - currentTime += 2000; // 2 seconds for relay propagation - flow.push({ - time: currentTime, - actor: `Relay (${nextRelays.join(', ')})`, - action: `Event available for ${nextThrowerName}`, - size: Math.max(nextRoutingSize, 0) - }); - } + // Step 4: Relay propagates to next superball + currentTime += 2000; // 2 seconds for relay propagation + flow.push({ + time: currentTime, + actor: `Relay (${forwardingRelays.join(', ')})`, + action: `Event available for ${nextThrowerName}`, + size: Math.max(nextRoutingSize, 0) + }); + } }); return flow; @@ -1827,6 +1875,11 @@ existingViz.remove(); } + // Refresh thrower status after reset so new dropdowns have current availability + setTimeout(() => { + discoverThrowers(); + }, 500); + console.log('INFO: Builder reset successfully'); } diff --git a/web/thrower.html b/web/thrower.html index ba899f8..9a115fe 100644 --- a/web/thrower.html +++ b/web/thrower.html @@ -2113,8 +2113,8 @@ item.status.charAt(0).toUpperCase() + item.status.slice(1); div.innerHTML = ` +
Status: ${statusText}
Event: ${item.id.substring(0, 32)}...
-
Status: ${statusText}
Target Relays: ${item.routing.relays.length}
Delay: ${item.routing.delay}s
${item.routing.padding ? `
Padding: ${item.routing.padding}
` : ''}