From a3e96c9895fe6e81e99e01a88e30baf098fa956e Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 14:12:15 +0100 Subject: [PATCH 01/18] add --- package-lock.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 209d0b25f..408816a2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18272,7 +18272,10 @@ }, "packages/ui-components": { "name": "@rainlanguage/ui-components", - "version": "0.0.1" + "version": "0.0.1", + "dependencies": { + "flowbite-svelte": "^0.44.21" + } }, "packages/webapp": { "name": "@rainlanguage/webapp", From 270add7109d330cbaa094197e49bb4522d93cedb Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 14:36:23 +0100 Subject: [PATCH 02/18] move in tests --- .../lib/components/TanstackAppTable.svelte | 70 ++++++ .../components/TanstackAppTable.test.svelte | 18 ++ .../lib/components/TanstackAppTable.test.ts | 237 ++++++++++++++++++ .../src/lib/components/icon/Refresh.svelte | 55 ++++ .../src/lib/mocks/MockComponent.svelte | 6 + .../src/lib/mocks/MockComponent.ts | 3 + .../ui-components/src/lib/mocks/queries.ts | 89 +++++++ .../ui-components/src/lib/mocks/settings.ts | 40 +++ .../ui-components/src/lib/mocks/wallets.ts | 10 + .../ui-components/src/lib/test/matchers.ts | 12 + packages/ui-components/vite.config.ts | 7 +- 11 files changed, 546 insertions(+), 1 deletion(-) create mode 100644 packages/ui-components/src/lib/components/TanstackAppTable.svelte create mode 100644 packages/ui-components/src/lib/components/TanstackAppTable.test.svelte create mode 100644 packages/ui-components/src/lib/components/TanstackAppTable.test.ts create mode 100644 packages/ui-components/src/lib/components/icon/Refresh.svelte create mode 100644 packages/ui-components/src/lib/mocks/MockComponent.svelte create mode 100644 packages/ui-components/src/lib/mocks/MockComponent.ts create mode 100644 packages/ui-components/src/lib/mocks/queries.ts create mode 100644 packages/ui-components/src/lib/mocks/settings.ts create mode 100644 packages/ui-components/src/lib/mocks/wallets.ts create mode 100644 packages/ui-components/src/lib/test/matchers.ts diff --git a/packages/ui-components/src/lib/components/TanstackAppTable.svelte b/packages/ui-components/src/lib/components/TanstackAppTable.svelte new file mode 100644 index 000000000..3d6d9918d --- /dev/null +++ b/packages/ui-components/src/lib/components/TanstackAppTable.svelte @@ -0,0 +1,70 @@ + + +
+ + + + { + $query.refetch(); + }} + /> +
+{#if $query.data?.pages[0].length === 0} +
+ {emptyMessage} +
+{:else if $query.data} + + + + + + {#each $query.data?.pages as page} + {#each page as item} + { + dispatch('clickRow', { item }); + }} + > + + + {/each} + {/each} + +
+
+ +
+{/if} diff --git a/packages/ui-components/src/lib/components/TanstackAppTable.test.svelte b/packages/ui-components/src/lib/components/TanstackAppTable.test.svelte new file mode 100644 index 000000000..656428ff4 --- /dev/null +++ b/packages/ui-components/src/lib/components/TanstackAppTable.test.svelte @@ -0,0 +1,18 @@ + + + + +

{title}

+
+ {head} + + {item} + +
diff --git a/packages/ui-components/src/lib/components/TanstackAppTable.test.ts b/packages/ui-components/src/lib/components/TanstackAppTable.test.ts new file mode 100644 index 000000000..e4a297ef0 --- /dev/null +++ b/packages/ui-components/src/lib/components/TanstackAppTable.test.ts @@ -0,0 +1,237 @@ +import { render, screen, waitFor } from '@testing-library/svelte'; +import { test, expect } from 'vitest'; +import TanstackAppTableTest from './TanstackAppTable.test.svelte'; +import userEvent from '@testing-library/user-event'; +import { createResolvableInfiniteQuery } from '../mocks/queries'; + +test('shows head and title', async () => { + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('head')).toHaveTextContent('Test head')); + expect(screen.getByTestId('title')).toHaveTextContent('Test Table'); +}); + +test('renders rows', async () => { + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); +}); + +test('shows empty message', async () => { + const { query, resolve } = createResolvableInfiniteQuery(() => { + return []; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('emptyMessage')).toHaveTextContent('No rows')); +}); + +test('loads more rows', async () => { + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); + + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + await userEvent.click(loadMoreButton); + + resolve(); + + await waitFor(() => { + expect(screen.getAllByTestId('bodyRow')).toHaveLength(2); + }); + + let rows = screen.getAllByTestId('bodyRow'); + + expect(rows).toHaveLength(2); + expect(rows[0]).toHaveTextContent('page0'); + expect(rows[1]).toHaveTextContent('page1'); + + // loading more rows + await userEvent.click(loadMoreButton); + + resolve(); + + await waitFor(() => { + expect(screen.getAllByTestId('bodyRow')).toHaveLength(3); + }); + + rows = screen.getAllByTestId('bodyRow'); + + expect(rows).toHaveLength(3); + expect(rows[0]).toHaveTextContent('page0'); + expect(rows[1]).toHaveTextContent('page1'); + expect(rows[2]).toHaveTextContent('page2'); +}); + +test('load more button message changes when loading', async () => { + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + + expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Load More'); + + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + await userEvent.click(loadMoreButton); + + expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Loading more...'); + + resolve(); + + await waitFor(() => { + expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Load More'); + }); +}); + +test('load more buttton is disabled when loading', async () => { + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); + + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + loadMoreButton.click(); + + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); +}); + +test('load more buttton is disabled when there are no more pages', async () => { + const { query, resolve } = createResolvableInfiniteQuery( + (pageParam) => { + if (!pageParam) return ['page' + pageParam]; + return []; + }, + (_lastPage, _allPages, lastPageParam) => { + if (lastPageParam === 0) return 1; + return undefined; + }, + ); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); + + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + loadMoreButton.click(); + + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); + + resolve(); + + await waitFor(() => + expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Nothing more to load'), + ); +}); + +test('refetches data when refresh button is clicked', async () => { + let refreshCount = 0; + const { query, resolve } = createResolvableInfiniteQuery(() => { + refreshCount++; + return ['refresh' + refreshCount]; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head', + }); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh1')); + + // refreshing + const refreshButton = screen.getByTestId('refreshButton'); + await userEvent.click(refreshButton); + + // refreshButton should have the class animate-spin + await waitFor(() => expect(refreshButton).toHaveClass('animate-spin')); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh2')); + + // refreshButton should not have the class animate-spin + await waitFor(() => expect(refreshButton).not.toHaveClass('animate-spin')); + + // refreshing + await userEvent.click(refreshButton); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh3')); +}); diff --git a/packages/ui-components/src/lib/components/icon/Refresh.svelte b/packages/ui-components/src/lib/components/icon/Refresh.svelte new file mode 100644 index 000000000..c07425d76 --- /dev/null +++ b/packages/ui-components/src/lib/components/icon/Refresh.svelte @@ -0,0 +1,55 @@ + + + + + + + diff --git a/packages/ui-components/src/lib/mocks/MockComponent.svelte b/packages/ui-components/src/lib/mocks/MockComponent.svelte new file mode 100644 index 000000000..942ae6023 --- /dev/null +++ b/packages/ui-components/src/lib/mocks/MockComponent.svelte @@ -0,0 +1,6 @@ + diff --git a/packages/ui-components/src/lib/mocks/MockComponent.ts b/packages/ui-components/src/lib/mocks/MockComponent.ts new file mode 100644 index 000000000..eb2e74c0d --- /dev/null +++ b/packages/ui-components/src/lib/mocks/MockComponent.ts @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export const props = writable(); diff --git a/packages/ui-components/src/lib/mocks/queries.ts b/packages/ui-components/src/lib/mocks/queries.ts new file mode 100644 index 000000000..2887c8b8d --- /dev/null +++ b/packages/ui-components/src/lib/mocks/queries.ts @@ -0,0 +1,89 @@ +import { QueryClient, createInfiniteQuery, createQuery } from '@tanstack/svelte-query'; + +// A helper function to create a resolvable mock query. +// This gives us more control over when each query resolves. +export const createResolvableMockQuery = (queryFn: (() => T) | ((pageParam: number) => T)) => { + const resolveQueue: Array<() => void> = []; + let currentPromise: Promise; + + const createNewPromise = () => { + currentPromise = new Promise((res) => { + resolveQueue.push(res); + }); + }; + + createNewPromise(); // Initialize the first promise + + const resolvableQuery = async (pageParam?: number) => { + const mockData = queryFn(pageParam as number); + await currentPromise; + createNewPromise(); // Create a new promise for the next call + return mockData; + }; + + const resolve = () => { + const resolver = resolveQueue.shift(); + if (resolver) { + resolver(); + } + }; + + return { queryFn: resolvableQuery, resolve }; +}; + +// A helper function to create an infinite Tanstack query that resolves when you call +// the `resolve` function. +export const createResolvableInfiniteQuery = ( + _queryFn: (pageParam: number) => unknown, + getNextPageParam: ( + _lastPage: unknown, + _allPages: unknown[], + lastPageParam: number, + ) => number | undefined = (_lastPage: unknown, _allPages: unknown[], lastPageParam: number) => + lastPageParam + 1, +) => { + const { queryFn, resolve } = createResolvableMockQuery(_queryFn); + + const query = createInfiniteQuery( + { + queryKey: [], + queryFn: ({ pageParam }) => { + return queryFn(pageParam); + }, + initialPageParam: 0, + getNextPageParam, + }, + new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + }, + }, + }), + ); + + return { query, resolve }; +}; + +// A helper function to create a regular Tanstack query that resolves when you call resolve +export const createResolvableQuery = (_queryFn: () => T) => { + const { queryFn, resolve } = createResolvableMockQuery(_queryFn); + + const query = createQuery( + { + queryKey: [], + queryFn: () => { + return queryFn(); + }, + }, + new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + }, + }, + }), + ); + + return { query, resolve }; +}; diff --git a/packages/ui-components/src/lib/mocks/settings.ts b/packages/ui-components/src/lib/mocks/settings.ts new file mode 100644 index 000000000..268865075 --- /dev/null +++ b/packages/ui-components/src/lib/mocks/settings.ts @@ -0,0 +1,40 @@ +import type { ConfigSource } from '$lib/typeshare/config'; +import { writable } from 'svelte/store'; + +export const mockConfigSource: ConfigSource = { + networks: { + mainnet: { + rpc: 'https://mainnet.infura.io/v3/YOUR-PROJECT-ID', + 'chain-id': 1, + label: 'Ethereum Mainnet', + currency: 'ETH', + }, + }, + subgraphs: { + mainnet: 'https://api.thegraph.com/subgraphs/name/mainnet', + }, + orderbooks: { + orderbook1: { + address: '0xOrderbookAddress1', + network: 'mainnet', + subgraph: 'uniswap', + label: 'Orderbook 1', + }, + }, + deployers: { + deployer1: { + address: '0xDeployerAddress1', + network: 'mainnet', + label: 'Deployer 1', + }, + }, + metaboards: { + metaboard1: 'https://example.com/metaboard1', + }, + accounts: { + name_one: 'address_one', + name_two: 'address_two', + }, +}; + +export const mockSettingsStore = writable(mockConfigSource); diff --git a/packages/ui-components/src/lib/mocks/wallets.ts b/packages/ui-components/src/lib/mocks/wallets.ts new file mode 100644 index 000000000..32b754ae8 --- /dev/null +++ b/packages/ui-components/src/lib/mocks/wallets.ts @@ -0,0 +1,10 @@ +import { writable } from 'svelte/store'; + +const mockWalletAddressMatchesOrBlankWritable = writable<() => boolean>(() => false); + +export const mockWalletAddressMatchesOrBlankStore = { + subscribe: mockWalletAddressMatchesOrBlankWritable.subscribe, + set: mockWalletAddressMatchesOrBlankWritable.set, + mockSetSubscribeValue: (value: () => boolean): void => + mockWalletAddressMatchesOrBlankWritable.set(value), +}; diff --git a/packages/ui-components/src/lib/test/matchers.ts b/packages/ui-components/src/lib/test/matchers.ts new file mode 100644 index 000000000..0bcffa9cc --- /dev/null +++ b/packages/ui-components/src/lib/test/matchers.ts @@ -0,0 +1,12 @@ +import { expect as vitestExpect } from 'vitest'; +import * as matchers from '@testing-library/jest-dom/matchers'; +vitestExpect.extend(matchers); + +export const expect = vitestExpect; + +declare module 'vitest' { + // vitest instead `@vitest/expect` + // eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-explicit-any + interface JestAssertion + extends matchers.TestingLibraryMatchers, T> {} +} diff --git a/packages/ui-components/vite.config.ts b/packages/ui-components/vite.config.ts index 704fe5ec9..09fa5170b 100644 --- a/packages/ui-components/vite.config.ts +++ b/packages/ui-components/vite.config.ts @@ -21,6 +21,11 @@ export default defineConfig(({ mode }) => ({ setupFiles: ['./test-setup.ts'], // load env vars env: loadEnv('', process.cwd(), ''), - testTimeout: 10000 + testTimeout: 10000, + server: { + deps: { + inline: [/@tanstack\/svelte-query/] + } + } } })); From b8e12924f6a0ac1c83b9d1fbdd101445e85ae933 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 15:04:07 +0100 Subject: [PATCH 03/18] working in tauri-app --- packages/ui-components/src/lib/index.ts | 1 + .../src/lib/mocks/MockComponent.svelte | 6 --- .../src/lib/mocks/MockComponent.ts | 3 -- .../ui-components/src/lib/mocks/settings.ts | 40 ------------------- .../ui-components/src/lib/mocks/wallets.ts | 10 ----- .../components/tables/OrdersListTable.svelte | 2 +- 6 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 packages/ui-components/src/lib/mocks/MockComponent.svelte delete mode 100644 packages/ui-components/src/lib/mocks/MockComponent.ts delete mode 100644 packages/ui-components/src/lib/mocks/settings.ts delete mode 100644 packages/ui-components/src/lib/mocks/wallets.ts diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index a220b3848..532b64895 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -1,3 +1,4 @@ import './app.css'; export { default as CardProperty } from './components/CardProperty.svelte'; export { default as Hash, HashType } from './components/Hash.svelte'; +export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; \ No newline at end of file diff --git a/packages/ui-components/src/lib/mocks/MockComponent.svelte b/packages/ui-components/src/lib/mocks/MockComponent.svelte deleted file mode 100644 index 942ae6023..000000000 --- a/packages/ui-components/src/lib/mocks/MockComponent.svelte +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/packages/ui-components/src/lib/mocks/MockComponent.ts b/packages/ui-components/src/lib/mocks/MockComponent.ts deleted file mode 100644 index eb2e74c0d..000000000 --- a/packages/ui-components/src/lib/mocks/MockComponent.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { writable } from 'svelte/store'; - -export const props = writable(); diff --git a/packages/ui-components/src/lib/mocks/settings.ts b/packages/ui-components/src/lib/mocks/settings.ts deleted file mode 100644 index 268865075..000000000 --- a/packages/ui-components/src/lib/mocks/settings.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { ConfigSource } from '$lib/typeshare/config'; -import { writable } from 'svelte/store'; - -export const mockConfigSource: ConfigSource = { - networks: { - mainnet: { - rpc: 'https://mainnet.infura.io/v3/YOUR-PROJECT-ID', - 'chain-id': 1, - label: 'Ethereum Mainnet', - currency: 'ETH', - }, - }, - subgraphs: { - mainnet: 'https://api.thegraph.com/subgraphs/name/mainnet', - }, - orderbooks: { - orderbook1: { - address: '0xOrderbookAddress1', - network: 'mainnet', - subgraph: 'uniswap', - label: 'Orderbook 1', - }, - }, - deployers: { - deployer1: { - address: '0xDeployerAddress1', - network: 'mainnet', - label: 'Deployer 1', - }, - }, - metaboards: { - metaboard1: 'https://example.com/metaboard1', - }, - accounts: { - name_one: 'address_one', - name_two: 'address_two', - }, -}; - -export const mockSettingsStore = writable(mockConfigSource); diff --git a/packages/ui-components/src/lib/mocks/wallets.ts b/packages/ui-components/src/lib/mocks/wallets.ts deleted file mode 100644 index 32b754ae8..000000000 --- a/packages/ui-components/src/lib/mocks/wallets.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { writable } from 'svelte/store'; - -const mockWalletAddressMatchesOrBlankWritable = writable<() => boolean>(() => false); - -export const mockWalletAddressMatchesOrBlankStore = { - subscribe: mockWalletAddressMatchesOrBlankWritable.subscribe, - set: mockWalletAddressMatchesOrBlankWritable.set, - mockSetSubscribeValue: (value: () => boolean): void => - mockWalletAddressMatchesOrBlankWritable.set(value), -}; diff --git a/tauri-app/src/lib/components/tables/OrdersListTable.svelte b/tauri-app/src/lib/components/tables/OrdersListTable.svelte index 34d890ddc..490a1f15f 100644 --- a/tauri-app/src/lib/components/tables/OrdersListTable.svelte +++ b/tauri-app/src/lib/components/tables/OrdersListTable.svelte @@ -3,7 +3,7 @@ import { ordersList } from '$lib/queries/ordersList'; import { createInfiniteQuery } from '@tanstack/svelte-query'; import { DEFAULT_PAGE_SIZE, DEFAULT_REFRESH_INTERVAL } from '$lib/queries/constants'; - import TanstackAppTable from './TanstackAppTable.svelte'; + import TanstackAppTable from '@rainlanguage/ui-components'; import { goto } from '$app/navigation'; import ListViewOrderbookSelector from '../ListViewOrderbookSelector.svelte'; import { From 1b172bb51309e7e6e937295b4d16e60d16314cd6 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 15:10:13 +0100 Subject: [PATCH 04/18] replace usage --- .../src/lib/components/TanstackAppTable.test.svelte | 1 - tauri-app/src/lib/components/tables/OrderTradesListTable.svelte | 2 +- tauri-app/src/lib/components/tables/OrderVaultsVolTable.svelte | 2 +- tauri-app/src/lib/components/tables/OrdersListTable.svelte | 2 +- .../src/lib/components/tables/VaultBalanceChangesTable.svelte | 2 +- tauri-app/src/lib/components/tables/VaultListTable.svelte | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/ui-components/src/lib/components/TanstackAppTable.test.svelte b/packages/ui-components/src/lib/components/TanstackAppTable.test.svelte index 656428ff4..c10d28ab1 100644 --- a/packages/ui-components/src/lib/components/TanstackAppTable.test.svelte +++ b/packages/ui-components/src/lib/components/TanstackAppTable.test.svelte @@ -1,6 +1,5 @@ - -
- - - - { - $query.refetch(); - }} - /> -
-{#if $query.data?.pages[0].length === 0} -
- {emptyMessage} -
-{:else if $query.data} - - - - - - {#each $query.data?.pages as page} - {#each page as item} - { - dispatch('clickRow', { item }); - }} - > - - - {/each} - {/each} - -
-
- -
-{/if} diff --git a/tauri-app/src/lib/components/tables/TanstackAppTable.test.svelte b/tauri-app/src/lib/components/tables/TanstackAppTable.test.svelte deleted file mode 100644 index 7ffe062e9..000000000 --- a/tauri-app/src/lib/components/tables/TanstackAppTable.test.svelte +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

{title}

-
- {head} - - {item} - -
diff --git a/tauri-app/src/lib/components/tables/TanstackAppTable.test.ts b/tauri-app/src/lib/components/tables/TanstackAppTable.test.ts deleted file mode 100644 index 51f6047c3..000000000 --- a/tauri-app/src/lib/components/tables/TanstackAppTable.test.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/svelte'; -import { test } from 'vitest'; -import { expect } from '$lib/test/matchers'; -import TanstackAppTableTest from './TanstackAppTable.test.svelte'; -import userEvent from '@testing-library/user-event'; -import { createResolvableInfiniteQuery } from '$lib/mocks/queries'; - -test('shows head and title', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('head')).toHaveTextContent('Test head')); - expect(screen.getByTestId('title')).toHaveTextContent('Test Table'); -}); - -test('renders rows', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); -}); - -test('shows empty message', async () => { - const { query, resolve } = createResolvableInfiniteQuery(() => { - return []; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('emptyMessage')).toHaveTextContent('No rows')); -}); - -test('loads more rows', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); - - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - await userEvent.click(loadMoreButton); - - resolve(); - - await waitFor(() => { - expect(screen.getAllByTestId('bodyRow')).toHaveLength(2); - }); - - let rows = screen.getAllByTestId('bodyRow'); - - expect(rows).toHaveLength(2); - expect(rows[0]).toHaveTextContent('page0'); - expect(rows[1]).toHaveTextContent('page1'); - - // loading more rows - await userEvent.click(loadMoreButton); - - resolve(); - - await waitFor(() => { - expect(screen.getAllByTestId('bodyRow')).toHaveLength(3); - }); - - rows = screen.getAllByTestId('bodyRow'); - - expect(rows).toHaveLength(3); - expect(rows[0]).toHaveTextContent('page0'); - expect(rows[1]).toHaveTextContent('page1'); - expect(rows[2]).toHaveTextContent('page2'); -}); - -test('load more button message changes when loading', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Load More'); - - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - await userEvent.click(loadMoreButton); - - expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Loading more...'); - - resolve(); - - await waitFor(() => { - expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Load More'); - }); -}); - -test('load more buttton is disabled when loading', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); - - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - loadMoreButton.click(); - - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); -}); - -test('load more buttton is disabled when there are no more pages', async () => { - const { query, resolve } = createResolvableInfiniteQuery( - (pageParam) => { - if (!pageParam) return ['page' + pageParam]; - return []; - }, - (_lastPage, _allPages, lastPageParam) => { - if (lastPageParam === 0) return 1; - return undefined; - }, - ); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); - - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - loadMoreButton.click(); - - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); - - resolve(); - - await waitFor(() => - expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Nothing more to load'), - ); -}); - -test('refetches data when refresh button is clicked', async () => { - let refreshCount = 0; - const { query, resolve } = createResolvableInfiniteQuery(() => { - refreshCount++; - return ['refresh' + refreshCount]; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh1')); - - // refreshing - const refreshButton = screen.getByTestId('refreshButton'); - await userEvent.click(refreshButton); - - // refreshButton should have the class animate-spin - await waitFor(() => expect(refreshButton).toHaveClass('animate-spin')); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh2')); - - // refreshButton should not have the class animate-spin - await waitFor(() => expect(refreshButton).not.toHaveClass('animate-spin')); - - // refreshing - await userEvent.click(refreshButton); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh3')); -}); From 6b09ddbcd018f84a08604dfdd2e36382ecfb22c6 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 15:57:09 +0100 Subject: [PATCH 06/18] add util --- packages/webapp/src/lib/utils/time.ts | 37 ++++++++++ packages/webapp/src/routes/+page.svelte | 93 +++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 packages/webapp/src/lib/utils/time.ts diff --git a/packages/webapp/src/lib/utils/time.ts b/packages/webapp/src/lib/utils/time.ts new file mode 100644 index 000000000..b04627713 --- /dev/null +++ b/packages/webapp/src/lib/utils/time.ts @@ -0,0 +1,37 @@ +import dayjs from 'dayjs'; +import bigIntSupport from 'dayjs/plugin/bigIntSupport'; +import localizedFormat from 'dayjs/plugin/localizedFormat'; +import type { UTCTimestamp } from 'lightweight-charts'; +dayjs.extend(bigIntSupport); +dayjs.extend(localizedFormat); + +export function formatTimestampSecondsAsLocal(timestampSeconds: bigint) { + return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); +} + +export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { + return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; +} + +/** + * Method to put a timeout on a promise, throws the exception if promise is not settled within the time + * @param promise - The original promise + * @param time - The time in ms + * @param exception - The exception to reject with if time runs out before original promise settlement + * @returns A new promise that gets settled with initial promise settlement or rejected with exception value + * if the time runs out before the main promise settlement + */ +export async function promiseTimeout( + promise: Promise, + time: number, + exception: unknown, +): Promise { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let timeout: any; + return Promise.race([ + promise, + new Promise( + (_resolve, reject) => (timeout = setTimeout(reject, time, exception)), + ) as Promise, + ]).finally(() => clearTimeout(timeout)); +} diff --git a/packages/webapp/src/routes/+page.svelte b/packages/webapp/src/routes/+page.svelte index e9dac81aa..19bfd729d 100644 --- a/packages/webapp/src/routes/+page.svelte +++ b/packages/webapp/src/routes/+page.svelte @@ -1,7 +1,92 @@ - -
- -
+ + + + + + + Network + Active + Order + Owner + Orderbook + Last Added + Input Token(s) + Output Token(s) + Trades + + + + + + {item.subgraphName} + + + {#if item.order.active} + Active + {:else} + Inactive + {/if} + + + + + + + + + + + + {formatTimestampSecondsAsLocal(BigInt(item.order.timestampAdded))} + + + {item.order.inputs?.map((t) => t.token.symbol)} + + + {item.order.outputs?.map((t) => t.token.symbol)} + + {item.order.trades.length > 99 ? '>99' : item.order.trades.length} + + From a506b0de222ed4e6f62871bda5cc13b3e2b2b7b2 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 15:59:06 +0100 Subject: [PATCH 07/18] hard code --- packages/webapp/src/routes/+page.svelte | 47 +++++++++++-------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/packages/webapp/src/routes/+page.svelte b/packages/webapp/src/routes/+page.svelte index 19bfd729d..358712b42 100644 --- a/packages/webapp/src/routes/+page.svelte +++ b/packages/webapp/src/routes/+page.svelte @@ -1,5 +1,5 @@ From 6105aaba4fa0f91978f77cbba534521064d8740e Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 16:04:40 +0100 Subject: [PATCH 08/18] hard code --- packages/webapp/src/routes/+page.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/webapp/src/routes/+page.svelte b/packages/webapp/src/routes/+page.svelte index 358712b42..df24e92ae 100644 --- a/packages/webapp/src/routes/+page.svelte +++ b/packages/webapp/src/routes/+page.svelte @@ -13,16 +13,16 @@ return getOrders( multiSubgraphArgs, { - owners: [connectedWalletAddress], + owners: [' '], active: true, orderHash: undefined }, - { page: pageParam + 1, pageSize: DEFAULT_PAGE_SIZE } + { page: pageParam + 1, pageSize: 1 } ); }, initialPageParam: 0, getNextPageParam(lastPage, _allPages, lastPageParam) { - return lastPage.length === DEFAULT_PAGE_SIZE ? lastPageParam + 1 : undefined; + return lastPage.length === 1 ? lastPageParam + 1 : undefined; }, refetchInterval: 10000, enabled: true From 59a17d85a2e6d7f079e99ffff1bba8af84c14e6c Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 16:30:10 +0100 Subject: [PATCH 09/18] format --- .../lib/components/TanstackAppTable.test.ts | 328 +++++++++--------- packages/ui-components/src/lib/index.ts | 2 +- .../ui-components/src/lib/mocks/queries.ts | 128 +++---- .../ui-components/src/lib/test/matchers.ts | 8 +- packages/webapp/src/lib/utils/time.ts | 24 +- packages/webapp/src/routes/+layout.svelte | 25 +- packages/webapp/src/routes/+page.svelte | 32 +- 7 files changed, 284 insertions(+), 263 deletions(-) diff --git a/packages/ui-components/src/lib/components/TanstackAppTable.test.ts b/packages/ui-components/src/lib/components/TanstackAppTable.test.ts index e4a297ef0..3029b6f5b 100644 --- a/packages/ui-components/src/lib/components/TanstackAppTable.test.ts +++ b/packages/ui-components/src/lib/components/TanstackAppTable.test.ts @@ -5,233 +5,233 @@ import userEvent from '@testing-library/user-event'; import { createResolvableInfiniteQuery } from '../mocks/queries'; test('shows head and title', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('head')).toHaveTextContent('Test head')); - expect(screen.getByTestId('title')).toHaveTextContent('Test Table'); + await waitFor(() => expect(screen.getByTestId('head')).toHaveTextContent('Test head')); + expect(screen.getByTestId('title')).toHaveTextContent('Test Table'); }); test('renders rows', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); + + resolve(); + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); }); test('shows empty message', async () => { - const { query, resolve } = createResolvableInfiniteQuery(() => { - return []; - }); + const { query, resolve } = createResolvableInfiniteQuery(() => { + return []; + }); - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('emptyMessage')).toHaveTextContent('No rows')); + await waitFor(() => expect(screen.getByTestId('emptyMessage')).toHaveTextContent('No rows')); }); test('loads more rows', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0')); - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - await userEvent.click(loadMoreButton); + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + await userEvent.click(loadMoreButton); - resolve(); + resolve(); - await waitFor(() => { - expect(screen.getAllByTestId('bodyRow')).toHaveLength(2); - }); + await waitFor(() => { + expect(screen.getAllByTestId('bodyRow')).toHaveLength(2); + }); - let rows = screen.getAllByTestId('bodyRow'); + let rows = screen.getAllByTestId('bodyRow'); - expect(rows).toHaveLength(2); - expect(rows[0]).toHaveTextContent('page0'); - expect(rows[1]).toHaveTextContent('page1'); + expect(rows).toHaveLength(2); + expect(rows[0]).toHaveTextContent('page0'); + expect(rows[1]).toHaveTextContent('page1'); - // loading more rows - await userEvent.click(loadMoreButton); + // loading more rows + await userEvent.click(loadMoreButton); - resolve(); + resolve(); - await waitFor(() => { - expect(screen.getAllByTestId('bodyRow')).toHaveLength(3); - }); + await waitFor(() => { + expect(screen.getAllByTestId('bodyRow')).toHaveLength(3); + }); - rows = screen.getAllByTestId('bodyRow'); + rows = screen.getAllByTestId('bodyRow'); - expect(rows).toHaveLength(3); - expect(rows[0]).toHaveTextContent('page0'); - expect(rows[1]).toHaveTextContent('page1'); - expect(rows[2]).toHaveTextContent('page2'); + expect(rows).toHaveLength(3); + expect(rows[0]).toHaveTextContent('page0'); + expect(rows[1]).toHaveTextContent('page1'); + expect(rows[2]).toHaveTextContent('page2'); }); test('load more button message changes when loading', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); - resolve(); + resolve(); - expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Load More'); + expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Load More'); - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - await userEvent.click(loadMoreButton); + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + await userEvent.click(loadMoreButton); - expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Loading more...'); + expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Loading more...'); - resolve(); + resolve(); - await waitFor(() => { - expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Load More'); - }); + await waitFor(() => { + expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Load More'); + }); }); test('load more buttton is disabled when loading', async () => { - const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { - return ['page' + pageParam]; - }); + const { query, resolve } = createResolvableInfiniteQuery((pageParam) => { + return ['page' + pageParam]; + }); - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - loadMoreButton.click(); + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + loadMoreButton.click(); - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); }); test('load more buttton is disabled when there are no more pages', async () => { - const { query, resolve } = createResolvableInfiniteQuery( - (pageParam) => { - if (!pageParam) return ['page' + pageParam]; - return []; - }, - (_lastPage, _allPages, lastPageParam) => { - if (lastPageParam === 0) return 1; - return undefined; - }, - ); - - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); - - resolve(); - - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); - - // loading more rows - const loadMoreButton = screen.getByTestId('loadMoreButton'); - loadMoreButton.click(); - - await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); - - resolve(); - - await waitFor(() => - expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Nothing more to load'), - ); + const { query, resolve } = createResolvableInfiniteQuery( + (pageParam) => { + if (!pageParam) return ['page' + pageParam]; + return []; + }, + (_lastPage, _allPages, lastPageParam) => { + if (lastPageParam === 0) return 1; + return undefined; + } + ); + + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); + + resolve(); + + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).not.toHaveAttribute('disabled')); + + // loading more rows + const loadMoreButton = screen.getByTestId('loadMoreButton'); + loadMoreButton.click(); + + await waitFor(() => expect(screen.getByTestId('loadMoreButton')).toHaveAttribute('disabled')); + + resolve(); + + await waitFor(() => + expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Nothing more to load') + ); }); test('refetches data when refresh button is clicked', async () => { - let refreshCount = 0; - const { query, resolve } = createResolvableInfiniteQuery(() => { - refreshCount++; - return ['refresh' + refreshCount]; - }); + let refreshCount = 0; + const { query, resolve } = createResolvableInfiniteQuery(() => { + refreshCount++; + return ['refresh' + refreshCount]; + }); - render(TanstackAppTableTest, { - query, - emptyMessage: 'No rows', - title: 'Test Table', - head: 'Test head', - }); + render(TanstackAppTableTest, { + query, + emptyMessage: 'No rows', + title: 'Test Table', + head: 'Test head' + }); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh1')); + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh1')); - // refreshing - const refreshButton = screen.getByTestId('refreshButton'); - await userEvent.click(refreshButton); + // refreshing + const refreshButton = screen.getByTestId('refreshButton'); + await userEvent.click(refreshButton); - // refreshButton should have the class animate-spin - await waitFor(() => expect(refreshButton).toHaveClass('animate-spin')); + // refreshButton should have the class animate-spin + await waitFor(() => expect(refreshButton).toHaveClass('animate-spin')); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh2')); + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh2')); - // refreshButton should not have the class animate-spin - await waitFor(() => expect(refreshButton).not.toHaveClass('animate-spin')); + // refreshButton should not have the class animate-spin + await waitFor(() => expect(refreshButton).not.toHaveClass('animate-spin')); - // refreshing - await userEvent.click(refreshButton); + // refreshing + await userEvent.click(refreshButton); - resolve(); + resolve(); - await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh3')); + await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('refresh3')); }); diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 532b64895..e55435f56 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -1,4 +1,4 @@ import './app.css'; export { default as CardProperty } from './components/CardProperty.svelte'; export { default as Hash, HashType } from './components/Hash.svelte'; -export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; \ No newline at end of file +export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; diff --git a/packages/ui-components/src/lib/mocks/queries.ts b/packages/ui-components/src/lib/mocks/queries.ts index 2887c8b8d..dec095f4b 100644 --- a/packages/ui-components/src/lib/mocks/queries.ts +++ b/packages/ui-components/src/lib/mocks/queries.ts @@ -3,87 +3,87 @@ import { QueryClient, createInfiniteQuery, createQuery } from '@tanstack/svelte- // A helper function to create a resolvable mock query. // This gives us more control over when each query resolves. export const createResolvableMockQuery = (queryFn: (() => T) | ((pageParam: number) => T)) => { - const resolveQueue: Array<() => void> = []; - let currentPromise: Promise; + const resolveQueue: Array<() => void> = []; + let currentPromise: Promise; - const createNewPromise = () => { - currentPromise = new Promise((res) => { - resolveQueue.push(res); - }); - }; + const createNewPromise = () => { + currentPromise = new Promise((res) => { + resolveQueue.push(res); + }); + }; - createNewPromise(); // Initialize the first promise + createNewPromise(); // Initialize the first promise - const resolvableQuery = async (pageParam?: number) => { - const mockData = queryFn(pageParam as number); - await currentPromise; - createNewPromise(); // Create a new promise for the next call - return mockData; - }; + const resolvableQuery = async (pageParam?: number) => { + const mockData = queryFn(pageParam as number); + await currentPromise; + createNewPromise(); // Create a new promise for the next call + return mockData; + }; - const resolve = () => { - const resolver = resolveQueue.shift(); - if (resolver) { - resolver(); - } - }; + const resolve = () => { + const resolver = resolveQueue.shift(); + if (resolver) { + resolver(); + } + }; - return { queryFn: resolvableQuery, resolve }; + return { queryFn: resolvableQuery, resolve }; }; // A helper function to create an infinite Tanstack query that resolves when you call // the `resolve` function. export const createResolvableInfiniteQuery = ( - _queryFn: (pageParam: number) => unknown, - getNextPageParam: ( - _lastPage: unknown, - _allPages: unknown[], - lastPageParam: number, - ) => number | undefined = (_lastPage: unknown, _allPages: unknown[], lastPageParam: number) => - lastPageParam + 1, + _queryFn: (pageParam: number) => unknown, + getNextPageParam: ( + _lastPage: unknown, + _allPages: unknown[], + lastPageParam: number + ) => number | undefined = (_lastPage: unknown, _allPages: unknown[], lastPageParam: number) => + lastPageParam + 1 ) => { - const { queryFn, resolve } = createResolvableMockQuery(_queryFn); + const { queryFn, resolve } = createResolvableMockQuery(_queryFn); - const query = createInfiniteQuery( - { - queryKey: [], - queryFn: ({ pageParam }) => { - return queryFn(pageParam); - }, - initialPageParam: 0, - getNextPageParam, - }, - new QueryClient({ - defaultOptions: { - queries: { - staleTime: Infinity, - }, - }, - }), - ); + const query = createInfiniteQuery( + { + queryKey: [], + queryFn: ({ pageParam }) => { + return queryFn(pageParam); + }, + initialPageParam: 0, + getNextPageParam + }, + new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity + } + } + }) + ); - return { query, resolve }; + return { query, resolve }; }; // A helper function to create a regular Tanstack query that resolves when you call resolve export const createResolvableQuery = (_queryFn: () => T) => { - const { queryFn, resolve } = createResolvableMockQuery(_queryFn); + const { queryFn, resolve } = createResolvableMockQuery(_queryFn); - const query = createQuery( - { - queryKey: [], - queryFn: () => { - return queryFn(); - }, - }, - new QueryClient({ - defaultOptions: { - queries: { - staleTime: Infinity, - }, - }, - }), - ); + const query = createQuery( + { + queryKey: [], + queryFn: () => { + return queryFn(); + } + }, + new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity + } + } + }) + ); - return { query, resolve }; + return { query, resolve }; }; diff --git a/packages/ui-components/src/lib/test/matchers.ts b/packages/ui-components/src/lib/test/matchers.ts index 0bcffa9cc..e6be01899 100644 --- a/packages/ui-components/src/lib/test/matchers.ts +++ b/packages/ui-components/src/lib/test/matchers.ts @@ -5,8 +5,8 @@ vitestExpect.extend(matchers); export const expect = vitestExpect; declare module 'vitest' { - // vitest instead `@vitest/expect` - // eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-explicit-any - interface JestAssertion - extends matchers.TestingLibraryMatchers, T> {} + // vitest instead `@vitest/expect` + // eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-explicit-any + interface JestAssertion + extends matchers.TestingLibraryMatchers, T> {} } diff --git a/packages/webapp/src/lib/utils/time.ts b/packages/webapp/src/lib/utils/time.ts index b04627713..8af50dafd 100644 --- a/packages/webapp/src/lib/utils/time.ts +++ b/packages/webapp/src/lib/utils/time.ts @@ -6,11 +6,11 @@ dayjs.extend(bigIntSupport); dayjs.extend(localizedFormat); export function formatTimestampSecondsAsLocal(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); + return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); } export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; + return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; } /** @@ -22,16 +22,14 @@ export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { * if the time runs out before the main promise settlement */ export async function promiseTimeout( - promise: Promise, - time: number, - exception: unknown, + promise: Promise, + time: number, + exception: unknown ): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let timeout: any; - return Promise.race([ - promise, - new Promise( - (_resolve, reject) => (timeout = setTimeout(reject, time, exception)), - ) as Promise, - ]).finally(() => clearTimeout(timeout)); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let timeout: any; + return Promise.race([ + promise, + new Promise((_resolve, reject) => (timeout = setTimeout(reject, time, exception))) as Promise + ]).finally(() => clearTimeout(timeout)); } diff --git a/packages/webapp/src/routes/+layout.svelte b/packages/webapp/src/routes/+layout.svelte index 1aa57ee5f..405eda876 100644 --- a/packages/webapp/src/routes/+layout.svelte +++ b/packages/webapp/src/routes/+layout.svelte @@ -1,11 +1,22 @@ -
-
- -
-
+ +
+
+ +
+
+
diff --git a/packages/webapp/src/routes/+page.svelte b/packages/webapp/src/routes/+page.svelte index df24e92ae..163e96b8f 100644 --- a/packages/webapp/src/routes/+page.svelte +++ b/packages/webapp/src/routes/+page.svelte @@ -1,19 +1,27 @@ - + @@ -84,4 +96,4 @@ >{item.order.trades.length > 99 ? '>99' : item.order.trades.length} - + From 134dd8c2a9c03535d68085f04e3cabae049fed25 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 16:32:26 +0100 Subject: [PATCH 10/18] format --- packages/ui-components/src/lib/index.ts | 2 +- packages/webapp/src/routes/+page.svelte | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index e55435f56..532b64895 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -1,4 +1,4 @@ import './app.css'; export { default as CardProperty } from './components/CardProperty.svelte'; export { default as Hash, HashType } from './components/Hash.svelte'; -export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; +export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; \ No newline at end of file diff --git a/packages/webapp/src/routes/+page.svelte b/packages/webapp/src/routes/+page.svelte index 163e96b8f..b68f57278 100644 --- a/packages/webapp/src/routes/+page.svelte +++ b/packages/webapp/src/routes/+page.svelte @@ -37,8 +37,6 @@ }); const AppTable = TanstackAppTable; - - $: console.log($query.data); From 3fa5f705b08ea00b853f7dda31b98f4af0de8d9a Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 18 Nov 2024 17:44:19 +0100 Subject: [PATCH 11/18] format --- packages/ui-components/src/lib/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 532b64895..e55435f56 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -1,4 +1,4 @@ import './app.css'; export { default as CardProperty } from './components/CardProperty.svelte'; export { default as Hash, HashType } from './components/Hash.svelte'; -export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; \ No newline at end of file +export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; From f6c70e1ff9edb86ba176fa31f90a51dcdcf74e5d Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 20 Nov 2024 11:57:35 +0100 Subject: [PATCH 12/18] move time to ui components --- packages/ui-components/src/lib/index.ts | 1 + .../src/lib/utils/time.ts | 24 ++++++++++--------- packages/webapp/src/routes/+page.svelte | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) rename packages/{webapp => ui-components}/src/lib/utils/time.ts (65%) diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index e55435f56..2c5c85774 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -2,3 +2,4 @@ import './app.css'; export { default as CardProperty } from './components/CardProperty.svelte'; export { default as Hash, HashType } from './components/Hash.svelte'; export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; +export { formatTimestampSecondsAsLocal, timestampSecondsToUTCTimestamp } from './utils/time'; \ No newline at end of file diff --git a/packages/webapp/src/lib/utils/time.ts b/packages/ui-components/src/lib/utils/time.ts similarity index 65% rename from packages/webapp/src/lib/utils/time.ts rename to packages/ui-components/src/lib/utils/time.ts index 8af50dafd..b04627713 100644 --- a/packages/webapp/src/lib/utils/time.ts +++ b/packages/ui-components/src/lib/utils/time.ts @@ -6,11 +6,11 @@ dayjs.extend(bigIntSupport); dayjs.extend(localizedFormat); export function formatTimestampSecondsAsLocal(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); + return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); } export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; + return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; } /** @@ -22,14 +22,16 @@ export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { * if the time runs out before the main promise settlement */ export async function promiseTimeout( - promise: Promise, - time: number, - exception: unknown + promise: Promise, + time: number, + exception: unknown, ): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let timeout: any; - return Promise.race([ - promise, - new Promise((_resolve, reject) => (timeout = setTimeout(reject, time, exception))) as Promise - ]).finally(() => clearTimeout(timeout)); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let timeout: any; + return Promise.race([ + promise, + new Promise( + (_resolve, reject) => (timeout = setTimeout(reject, time, exception)), + ) as Promise, + ]).finally(() => clearTimeout(timeout)); } diff --git a/packages/webapp/src/routes/+page.svelte b/packages/webapp/src/routes/+page.svelte index b68f57278..73c38732d 100644 --- a/packages/webapp/src/routes/+page.svelte +++ b/packages/webapp/src/routes/+page.svelte @@ -5,7 +5,7 @@ import { TanstackAppTable } from '@rainlanguage/ui-components'; import { Badge, TableBodyCell, TableHeadCell } from 'flowbite-svelte'; - import { formatTimestampSecondsAsLocal } from '../lib/utils/time'; + import { formatTimestampSecondsAsLocal } from '@rainlanguage/ui-components'; import { Hash, HashType } from '@rainlanguage/ui-components'; const multiSubgraphArgs: MultiSubgraphArgs[] = [ From ff48dbb6e13929faa17c562a110c89a49ac4e2e9 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 20 Nov 2024 11:58:16 +0100 Subject: [PATCH 13/18] format lib utils --- packages/ui-components/src/lib/index.ts | 2 +- packages/ui-components/src/lib/utils/time.ts | 24 +++++++++----------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 2c5c85774..71632914d 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -2,4 +2,4 @@ import './app.css'; export { default as CardProperty } from './components/CardProperty.svelte'; export { default as Hash, HashType } from './components/Hash.svelte'; export { default as TanstackAppTable } from './components/TanstackAppTable.svelte'; -export { formatTimestampSecondsAsLocal, timestampSecondsToUTCTimestamp } from './utils/time'; \ No newline at end of file +export { formatTimestampSecondsAsLocal, timestampSecondsToUTCTimestamp } from './utils/time'; diff --git a/packages/ui-components/src/lib/utils/time.ts b/packages/ui-components/src/lib/utils/time.ts index b04627713..8af50dafd 100644 --- a/packages/ui-components/src/lib/utils/time.ts +++ b/packages/ui-components/src/lib/utils/time.ts @@ -6,11 +6,11 @@ dayjs.extend(bigIntSupport); dayjs.extend(localizedFormat); export function formatTimestampSecondsAsLocal(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); + return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); } export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; + return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; } /** @@ -22,16 +22,14 @@ export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { * if the time runs out before the main promise settlement */ export async function promiseTimeout( - promise: Promise, - time: number, - exception: unknown, + promise: Promise, + time: number, + exception: unknown ): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let timeout: any; - return Promise.race([ - promise, - new Promise( - (_resolve, reject) => (timeout = setTimeout(reject, time, exception)), - ) as Promise, - ]).finally(() => clearTimeout(timeout)); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let timeout: any; + return Promise.race([ + promise, + new Promise((_resolve, reject) => (timeout = setTimeout(reject, time, exception))) as Promise + ]).finally(() => clearTimeout(timeout)); } From 914be84212b64ee519d1ca633fc70623f3a45b9f Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 20 Nov 2024 13:22:15 +0100 Subject: [PATCH 14/18] remove all use of $lib/time --- tauri-app/src/lib/components/TradesTable.svelte | 2 +- tauri-app/src/lib/components/charts/VaultBalanceChart.svelte | 2 +- tauri-app/src/lib/components/charts/VaultBalanceChart.test.ts | 2 +- tauri-app/src/lib/components/detail/OrderDetail.svelte | 2 +- tauri-app/src/lib/components/detail/OrderDetail.test.ts | 2 +- tauri-app/src/lib/components/tables/OrderTradesListTable.svelte | 2 +- tauri-app/src/lib/components/tables/OrdersListTable.svelte | 2 +- tauri-app/src/lib/components/tables/OrdersListTable.test.ts | 2 +- .../src/lib/components/tables/VaultBalanceChangesTable.svelte | 2 +- .../src/lib/components/tables/VaultBalanceChangesTable.test.ts | 2 +- tauri-app/src/lib/services/historicalOrderCharts.ts | 2 +- tauri-app/src/routes/orders/add/+page.svelte | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tauri-app/src/lib/components/TradesTable.svelte b/tauri-app/src/lib/components/TradesTable.svelte index 0f34cfbdb..bbb52ffa6 100644 --- a/tauri-app/src/lib/components/TradesTable.svelte +++ b/tauri-app/src/lib/components/TradesTable.svelte @@ -1,6 +1,6 @@ - - - - - - diff --git a/tauri-app/src/lib/components/modal/ModalQuoteDebug.svelte b/tauri-app/src/lib/components/modal/ModalQuoteDebug.svelte index 4da4df858..ce3f18b6e 100644 --- a/tauri-app/src/lib/components/modal/ModalQuoteDebug.svelte +++ b/tauri-app/src/lib/components/modal/ModalQuoteDebug.svelte @@ -5,7 +5,7 @@ import { createQuery } from '@tanstack/svelte-query'; import { Alert, Modal } from 'flowbite-svelte'; import { type Hex } from 'viem'; - import {Refresh} from '@rainlanguage/ui-components'; + import { Refresh } from '@rainlanguage/ui-components'; import EvalResultsTable from '../debug/EvalResultsTable.svelte'; import { fade } from 'svelte/transition'; diff --git a/tauri-app/src/lib/mocks/queries.ts b/tauri-app/src/lib/mocks/queries.ts deleted file mode 100644 index 2887c8b8d..000000000 --- a/tauri-app/src/lib/mocks/queries.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { QueryClient, createInfiniteQuery, createQuery } from '@tanstack/svelte-query'; - -// A helper function to create a resolvable mock query. -// This gives us more control over when each query resolves. -export const createResolvableMockQuery = (queryFn: (() => T) | ((pageParam: number) => T)) => { - const resolveQueue: Array<() => void> = []; - let currentPromise: Promise; - - const createNewPromise = () => { - currentPromise = new Promise((res) => { - resolveQueue.push(res); - }); - }; - - createNewPromise(); // Initialize the first promise - - const resolvableQuery = async (pageParam?: number) => { - const mockData = queryFn(pageParam as number); - await currentPromise; - createNewPromise(); // Create a new promise for the next call - return mockData; - }; - - const resolve = () => { - const resolver = resolveQueue.shift(); - if (resolver) { - resolver(); - } - }; - - return { queryFn: resolvableQuery, resolve }; -}; - -// A helper function to create an infinite Tanstack query that resolves when you call -// the `resolve` function. -export const createResolvableInfiniteQuery = ( - _queryFn: (pageParam: number) => unknown, - getNextPageParam: ( - _lastPage: unknown, - _allPages: unknown[], - lastPageParam: number, - ) => number | undefined = (_lastPage: unknown, _allPages: unknown[], lastPageParam: number) => - lastPageParam + 1, -) => { - const { queryFn, resolve } = createResolvableMockQuery(_queryFn); - - const query = createInfiniteQuery( - { - queryKey: [], - queryFn: ({ pageParam }) => { - return queryFn(pageParam); - }, - initialPageParam: 0, - getNextPageParam, - }, - new QueryClient({ - defaultOptions: { - queries: { - staleTime: Infinity, - }, - }, - }), - ); - - return { query, resolve }; -}; - -// A helper function to create a regular Tanstack query that resolves when you call resolve -export const createResolvableQuery = (_queryFn: () => T) => { - const { queryFn, resolve } = createResolvableMockQuery(_queryFn); - - const query = createQuery( - { - queryKey: [], - queryFn: () => { - return queryFn(); - }, - }, - new QueryClient({ - defaultOptions: { - queries: { - staleTime: Infinity, - }, - }, - }), - ); - - return { query, resolve }; -}; From f4e1f6213629ecff1fcb1a13f1ed05588124861c Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 20 Nov 2024 13:44:57 +0100 Subject: [PATCH 17/18] change deprecated vite config thing --- tauri-app/vite.config.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tauri-app/vite.config.ts b/tauri-app/vite.config.ts index 2e03c1fc8..ab86b5fbf 100644 --- a/tauri-app/vite.config.ts +++ b/tauri-app/vite.config.ts @@ -55,8 +55,10 @@ export default defineConfig(({ mode }) => { includeSource: ['src/**/*.{js,ts}'], environment: 'jsdom', setupFiles: ['./vitest-setup.ts'], - deps: { - inline: [/@sveltejs\/kit/, /@tanstack\/svelte-query/], + server: { + deps: { + inline: [/@sveltejs\/kit/, /@tanstack\/svelte-query/], + } }, }, From 2011dbe2256af1c4cb707829ffcb49a8dc7b2be0 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 20 Nov 2024 13:47:40 +0100 Subject: [PATCH 18/18] delete time --- tauri-app/src/lib/utils/time.ts | 37 --------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 tauri-app/src/lib/utils/time.ts diff --git a/tauri-app/src/lib/utils/time.ts b/tauri-app/src/lib/utils/time.ts deleted file mode 100644 index b04627713..000000000 --- a/tauri-app/src/lib/utils/time.ts +++ /dev/null @@ -1,37 +0,0 @@ -import dayjs from 'dayjs'; -import bigIntSupport from 'dayjs/plugin/bigIntSupport'; -import localizedFormat from 'dayjs/plugin/localizedFormat'; -import type { UTCTimestamp } from 'lightweight-charts'; -dayjs.extend(bigIntSupport); -dayjs.extend(localizedFormat); - -export function formatTimestampSecondsAsLocal(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).format('L LT'); -} - -export function timestampSecondsToUTCTimestamp(timestampSeconds: bigint) { - return dayjs(timestampSeconds * BigInt('1000')).unix() as UTCTimestamp; -} - -/** - * Method to put a timeout on a promise, throws the exception if promise is not settled within the time - * @param promise - The original promise - * @param time - The time in ms - * @param exception - The exception to reject with if time runs out before original promise settlement - * @returns A new promise that gets settled with initial promise settlement or rejected with exception value - * if the time runs out before the main promise settlement - */ -export async function promiseTimeout( - promise: Promise, - time: number, - exception: unknown, -): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let timeout: any; - return Promise.race([ - promise, - new Promise( - (_resolve, reject) => (timeout = setTimeout(reject, time, exception)), - ) as Promise, - ]).finally(() => clearTimeout(timeout)); -}