diff --git a/crates/js_api/src/gui/mod.rs b/crates/js_api/src/gui/mod.rs index d28888c0d..76f7d7170 100644 --- a/crates/js_api/src/gui/mod.rs +++ b/crates/js_api/src/gui/mod.rs @@ -173,6 +173,17 @@ impl DotrainOrderGui { ); Ok(dotrain) } + + #[wasm_bindgen(js_name = "getComposedRainlang")] + pub async fn get_composed_rainlang(&mut self) -> Result { + self.update_scenario_bindings()?; + let dotrain = self.generate_dotrain_text()?; + let dotrain_order = DotrainOrder::new(dotrain, None).await?; + let rainlang = dotrain_order + .compose_deployment_to_rainlang(self.selected_deployment.clone()) + .await?; + Ok(rainlang) + } } #[derive(Error, Debug)] diff --git a/crates/js_api/src/gui/order_operations.rs b/crates/js_api/src/gui/order_operations.rs index f2a04e161..bbe4fbcf0 100644 --- a/crates/js_api/src/gui/order_operations.rs +++ b/crates/js_api/src/gui/order_operations.rs @@ -43,6 +43,10 @@ impl_all_wasm_traits!(AddOrderCalldataResult); pub struct DepositAndAddOrderCalldataResult(Bytes); impl_all_wasm_traits!(DepositAndAddOrderCalldataResult); +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Tsify)] +pub struct IOVaultIds(HashMap>>); +impl_all_wasm_traits!(IOVaultIds); + #[wasm_bindgen] impl DotrainOrderGui { fn get_orderbook(&self) -> Result, GuiError> { @@ -316,6 +320,34 @@ impl DotrainOrderGui { Ok(()) } + #[wasm_bindgen(js_name = "getVaultIds")] + pub fn get_vault_ids(&self) -> Result { + let deployment = self.get_current_deployment()?; + let map = HashMap::from([ + ( + "input".to_string(), + deployment + .deployment + .order + .inputs + .iter() + .map(|input| input.vault_id.clone()) + .collect(), + ), + ( + "output".to_string(), + deployment + .deployment + .order + .outputs + .iter() + .map(|output| output.vault_id.clone()) + .collect(), + ), + ]); + Ok(IOVaultIds(map)) + } + #[wasm_bindgen(js_name = "updateScenarioBindings")] pub fn update_scenario_bindings(&mut self) -> Result<(), GuiError> { let deployment = self.get_current_deployment()?; diff --git a/crates/js_api/src/gui/select_tokens.rs b/crates/js_api/src/gui/select_tokens.rs index 689e70af4..67a920764 100644 --- a/crates/js_api/src/gui/select_tokens.rs +++ b/crates/js_api/src/gui/select_tokens.rs @@ -113,4 +113,15 @@ impl DotrainOrderGui { Token::remove_record_from_yaml(self.dotrain_order.orderbook_yaml().documents, &key)?; Ok(()) } + + #[wasm_bindgen(js_name = "areAllTokensSelected")] + pub fn are_all_tokens_selected(&self) -> Result { + let select_tokens = self.get_select_tokens()?; + for token in select_tokens.0 { + if !self.is_select_token_set(token.key)? { + return Ok(false); + } + } + Ok(true) + } } diff --git a/packages/orderbook/test/js_api/gui.test.ts b/packages/orderbook/test/js_api/gui.test.ts index 6ea199ad1..192a24c70 100644 --- a/packages/orderbook/test/js_api/gui.test.ts +++ b/packages/orderbook/test/js_api/gui.test.ts @@ -12,6 +12,7 @@ import { DepositCalldataResult, Gui, GuiDeployment, + IOVaultIds, NameAndDescription, TokenDeposit, TokenInfo @@ -1183,17 +1184,22 @@ ${dotrainWithoutVaultIds}`; assert.equal(currentDeployment.deployment.order.inputs[0].vaultId, undefined); assert.equal(currentDeployment.deployment.order.outputs[0].vaultId, undefined); - gui.setVaultId(true, 0, '0x123123123456456456'); - gui.setVaultId(false, 0, '0x123123123456456456'); + gui.setVaultId(true, 0, '0x123'); + + assert.equal(gui.getVaultIds().get('input')?.[0], '0x123'); + assert.equal(gui.getVaultIds().get('output')?.[0], undefined); + + gui.setVaultId(false, 0, '0x234'); let newCurrentDeployment: GuiDeployment = gui.getCurrentDeployment(); assert.notEqual(newCurrentDeployment.deployment.order.inputs[0].vaultId, undefined); assert.notEqual(newCurrentDeployment.deployment.order.outputs[0].vaultId, undefined); - assert.equal(newCurrentDeployment.deployment.order.inputs[0].vaultId, '0x123123123456456456'); - assert.equal( - newCurrentDeployment.deployment.order.outputs[0].vaultId, - '0x123123123456456456' - ); + assert.equal(newCurrentDeployment.deployment.order.inputs[0].vaultId, '0x123'); + assert.equal(newCurrentDeployment.deployment.order.outputs[0].vaultId, '0x234'); + + const vaultIds: IOVaultIds = gui.getVaultIds(); + assert.equal(vaultIds.get('input')?.[0], '0x123'); + assert.equal(vaultIds.get('output')?.[0], '0x234'); }); it('should skip deposits with zero amount for deposit calldata', async () => { @@ -1280,6 +1286,7 @@ ${dotrainWithoutVaultIds}`; assert.equal(gui.isSelectTokenSet('token1'), false); assert.equal(gui.isSelectTokenSet('token2'), false); + assert.equal(gui.areAllTokensSelected(), false); await expect(async () => await gui.getTokenInfo('token1')).rejects.toThrow( "Missing required field 'tokens' in root" @@ -1293,6 +1300,7 @@ ${dotrainWithoutVaultIds}`; assert.equal(gui.isSelectTokenSet('token1'), true); assert.equal(gui.isSelectTokenSet('token2'), true); + assert.equal(gui.areAllTokensSelected(), true); let tokenInfo: TokenInfo = await gui.getTokenInfo('token1'); assert.equal(tokenInfo.name, 'Token 1'); diff --git a/packages/ui-components/src/__tests__/ComposedRainlangModal.test.ts b/packages/ui-components/src/__tests__/ComposedRainlangModal.test.ts index 005a8cc25..96950dca5 100644 --- a/packages/ui-components/src/__tests__/ComposedRainlangModal.test.ts +++ b/packages/ui-components/src/__tests__/ComposedRainlangModal.test.ts @@ -1,24 +1,26 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, fireEvent, waitFor } from '@testing-library/svelte'; import ComposedRainlangModal from '../lib/components/deployment/ComposedRainlangModal.svelte'; +import type { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; vi.mock('svelte-codemirror-editor', async () => { const mockCodeMirror = (await import('../lib/__mocks__/MockComponent.svelte')).default; return { default: mockCodeMirror }; }); -describe('ComposedRainlangModal', () => { - let composeRainlangMock: ReturnType; +const mockGui = { + getComposedRainlang: vi.fn(() => Promise.resolve('mocked rainlang text')) +} as unknown as DotrainOrderGui; +describe('ComposedRainlangModal', () => { beforeEach(() => { - composeRainlangMock = vi.fn(() => Promise.resolve('mocked rainlang text')); vi.clearAllMocks(); }); it('should open modal and display rainlang text when button is clicked', async () => { const { getByText, getByTestId } = render(ComposedRainlangModal, { props: { - composeRainlang: composeRainlangMock, + gui: mockGui, codeMirrorStyles: {} } }); @@ -27,7 +29,7 @@ describe('ComposedRainlangModal', () => { await fireEvent.click(button); await waitFor(() => { - expect(composeRainlangMock).toHaveBeenCalled(); + expect(mockGui.getComposedRainlang).toHaveBeenCalled(); expect(getByTestId('modal')).toBeInTheDocument(); }); }); diff --git a/packages/ui-components/src/__tests__/TokenIOInput.test.ts b/packages/ui-components/src/__tests__/TokenIOInput.test.ts index 1dc93a904..523b855ef 100644 --- a/packages/ui-components/src/__tests__/TokenIOInput.test.ts +++ b/packages/ui-components/src/__tests__/TokenIOInput.test.ts @@ -2,7 +2,6 @@ import { render, fireEvent, waitFor } from '@testing-library/svelte'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import TokenIOInput from '../lib/components/deployment/TokenIOInput.svelte'; import type { ComponentProps } from 'svelte'; -import userEvent from '@testing-library/user-event'; export type TokenIOInputComponentProps = ComponentProps; @@ -28,25 +27,27 @@ describe('TokenInput', () => { inputs: [mockInput] } } - }) + }), + getVaultIds: vi.fn().mockReturnValue( + new Map([ + ['input', ['vault1']], + ['output', ['vault2']] + ]) + ) }; const mockProps: TokenIOInputComponentProps = { i: 0, - isInput: true, label: 'Input', vault: mockInput, - vaultIds: ['vault1'], gui: mockGui, handleUpdateGuiState: vi.fn() } as unknown as TokenIOInputComponentProps; const outputMockProps: TokenIOInputComponentProps = { i: 0, - isInput: false, label: 'Output', vault: mockInput, - vaultIds: ['vault2'], gui: mockGui, handleUpdateGuiState: vi.fn() } as unknown as TokenIOInputComponentProps; @@ -75,13 +76,9 @@ describe('TokenInput', () => { }); it('calls setVaultId when input changes', async () => { - const { getByPlaceholderText } = render(TokenIOInput, mockProps); - const input = getByPlaceholderText('Enter vault ID'); - - await userEvent.type(input, 'vault1'); - await waitFor(() => { - expect(mockGui.setVaultId).toHaveBeenCalledWith(true, 0, 'vault1'); - }); + const input = render(TokenIOInput, mockProps).getByPlaceholderText('Enter vault ID'); + await fireEvent.input(input, { target: { value: 'vault1' } }); + expect(mockGui.setVaultId).toHaveBeenCalledWith(true, 0, 'vault1'); }); it('calls setVaultId on output vault when input changes', async () => { diff --git a/packages/ui-components/src/lib/components/deployment/ComposedRainlangModal.svelte b/packages/ui-components/src/lib/components/deployment/ComposedRainlangModal.svelte index b1b66796e..04b443e27 100644 --- a/packages/ui-components/src/lib/components/deployment/ComposedRainlangModal.svelte +++ b/packages/ui-components/src/lib/components/deployment/ComposedRainlangModal.svelte @@ -3,15 +3,17 @@ import { RainlangLR } from 'codemirror-rainlang'; import { lightCodeMirrorTheme } from '../../utils/codeMirrorThemes'; import { Button, Modal } from 'flowbite-svelte'; + import type { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; - export let composeRainlang: () => Promise; + export let gui: DotrainOrderGui; export let codeMirrorStyles = {}; let rainlangText: string | null = null; let open = false; async function generateRainlang() { - const rainlang = await composeRainlang(); + if (!gui) return; + const rainlang = await gui.getComposedRainlang(); if (rainlang) { rainlangText = rainlang; open = true; diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index 8ae60b133..c8e2454ba 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -14,7 +14,6 @@ type OrderIO, type ApprovalCalldataResult, type DepositAndAddOrderCalldataResult, - DotrainOrder, type SelectTokens } from '@rainlanguage/orderbook/js_api'; import { fade } from 'svelte/transition'; @@ -220,18 +219,12 @@ const areAllTokensSelected = async () => { if (gui) { try { - selectTokens = await gui.getSelectTokens(); - if (selectTokens?.every((t) => gui?.isSelectTokenSet(t.key))) { - allTokensSelected = true; - } + allTokensSelected = gui?.areAllTokensSelected(); + const vaultIds = gui?.getVaultIds(); + const inputVaultIds = vaultIds?.get('input'); + const outputVaultIds = vaultIds?.get('output'); // if we have deposits or vault ids set, show advanced options const deposits = gui?.getDeposits(); - const inputVaultIds = gui - ?.getCurrentDeployment() - ?.deployment?.order?.inputs.map((input) => input.vaultId); - const outputVaultIds = gui - ?.getCurrentDeployment() - ?.deployment?.order?.outputs.map((output) => output.vaultId); if (deposits || inputVaultIds || outputVaultIds) { showAdvancedOptions = true; } @@ -241,16 +234,6 @@ } } }; - - async function composeRainlang() { - if (!gui) return; - gui.updateScenarioBindings(); - const deployment = gui.getCurrentDeployment(); - const dotrain = gui.generateDotrainText(); - const dotrainOrder = await DotrainOrder.create(dotrain); - const composedRainlang = await dotrainOrder.composeDeploymentToRainlang(deployment.key); - return composedRainlang; - }
@@ -296,7 +279,7 @@
{#if $wagmiConnected} - + {:else} {/if} diff --git a/packages/ui-components/src/lib/components/deployment/TokenIOInput.svelte b/packages/ui-components/src/lib/components/deployment/TokenIOInput.svelte index 26350b2f2..886ccbc6e 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenIOInput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenIOInput.svelte @@ -19,10 +19,12 @@ let error: string = ''; onMount(() => { + if (!gui) return; + const vaultIds = gui.getVaultIds(); if (label === 'Input') { - inputValue = gui?.getCurrentDeployment()?.deployment?.order?.inputs[i]?.vaultId; + inputValue = vaultIds.get('input')?.[i]; } else if (label === 'Output') { - inputValue = gui?.getCurrentDeployment()?.deployment?.order?.outputs[i]?.vaultId; + inputValue = vaultIds.get('output')?.[i]; } });