Problem
The Deploy Order button in the deployment flow is enabled whether or not the deployment is actually valid. Validation happens after the click, so the user is offered an action that cannot succeed and is answered with an error.
packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte:312-325
<Button
data-testid="deploy-button"
size="lg"
disabled={checkingDeployment}
on:click={handleDeployButtonClick}
>
disabled is bound only to checkingDeployment — the in-flight spinner state. handleDeployButtonClick (L224-244) then checks only the wallet connection before delegating to onDeploy(raindexClient, builder); the real validation runs downstream in handleAddOrder.ts via builder.getDeploymentTransactionArgs(account), and failures surface as a DeploymentStepsError alert / errToast.
What is already gated (and what isn't)
Some preconditions are enforced structurally, by hiding the block rather than disabling the button:
- Token selection — the whole section, button included, is wrapped in
{#if allTokensSelected || selectTokens?.length === 0} (L274).
- Wallet connection —
{#if $account} swaps the button for <WalletConnect> (L311).
What is not gated is the state of the deployment inputs themselves: allFieldDefinitionsWithoutDefaults is rendered as a list of FieldDefinitionInputs (L275-279) with no check that the user supplied values, and deposit amounts are likewise unchecked. There is no validity state in the component at all — no isValid, canDeploy, or equivalent.
Suggested fix
Derive a single reactive validity value (all required field definitions have values, deposits parse, tokens selected) and bind the button to it:
disabled={checkingDeployment || !canDeploy}
Keeping the post-click error path as a backstop is fine — this is about not offering an action that is known to fail. Ideally the unmet precondition is also named (e.g. a hint under the button) so a disabled button isn't a dead end.
Context
Split out of #183, which asked for this on the Tauri app's "Add Order" button and its dotrain lint diagnostics. That surface no longer exists (the Tauri app was removed in 2a319034), and rainlang-level validity is already handled structurally — orders whose rainlang fails to parse are rendered in a non-clickable "Invalid orders in rainlang" panel and have no route to a deploy page. This issue covers the remaining, different gap on the current surface: GUI field validation does not gate the deploy control.
Problem
The Deploy Order button in the deployment flow is enabled whether or not the deployment is actually valid. Validation happens after the click, so the user is offered an action that cannot succeed and is answered with an error.
packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte:312-325disabledis bound only tocheckingDeployment— the in-flight spinner state.handleDeployButtonClick(L224-244) then checks only the wallet connection before delegating toonDeploy(raindexClient, builder); the real validation runs downstream inhandleAddOrder.tsviabuilder.getDeploymentTransactionArgs(account), and failures surface as aDeploymentStepsErroralert /errToast.What is already gated (and what isn't)
Some preconditions are enforced structurally, by hiding the block rather than disabling the button:
{#if allTokensSelected || selectTokens?.length === 0}(L274).{#if $account}swaps the button for<WalletConnect>(L311).What is not gated is the state of the deployment inputs themselves:
allFieldDefinitionsWithoutDefaultsis rendered as a list ofFieldDefinitionInputs (L275-279) with no check that the user supplied values, and deposit amounts are likewise unchecked. There is no validity state in the component at all — noisValid,canDeploy, or equivalent.Suggested fix
Derive a single reactive validity value (all required field definitions have values, deposits parse, tokens selected) and bind the button to it:
disabled={checkingDeployment || !canDeploy}Keeping the post-click error path as a backstop is fine — this is about not offering an action that is known to fail. Ideally the unmet precondition is also named (e.g. a hint under the button) so a disabled button isn't a dead end.
Context
Split out of #183, which asked for this on the Tauri app's "Add Order" button and its dotrain lint diagnostics. That surface no longer exists (the Tauri app was removed in
2a319034), and rainlang-level validity is already handled structurally — orders whose rainlang fails to parse are rendered in a non-clickable "Invalid orders in rainlang" panel and have no route to a deploy page. This issue covers the remaining, different gap on the current surface: GUI field validation does not gate the deploy control.