diff --git a/.changeset/cool-avocados-teach.md b/.changeset/cool-avocados-teach.md new file mode 100644 index 000000000..e984e0e92 --- /dev/null +++ b/.changeset/cool-avocados-teach.md @@ -0,0 +1,5 @@ +--- +'renterd': minor +--- + +Max RPC price and max contract price now show a suggestion instead of a network average. diff --git a/.changeset/popular-rocks-tie.md b/.changeset/popular-rocks-tie.md new file mode 100644 index 000000000..109d06fe3 --- /dev/null +++ b/.changeset/popular-rocks-tie.md @@ -0,0 +1,5 @@ +--- +'renterd': patch +--- + +Fixed a bug where the network average prices would show as 0 in the configuration fields. Closes https://github.com/SiaFoundation/renterd/issues/1565 diff --git a/apps/hostd-e2e/src/fixtures/configResetAllSettings.ts b/apps/hostd-e2e/src/fixtures/configResetAllSettings.ts index 3e3502935..4b17c91d5 100644 --- a/apps/hostd-e2e/src/fixtures/configResetAllSettings.ts +++ b/apps/hostd-e2e/src/fixtures/configResetAllSettings.ts @@ -3,7 +3,6 @@ import { setSwitchByLabel } from './switchValue' import { setViewMode } from './configViewMode' import { fillTextInputByName } from './textInput' import { fillSelectInputByName } from './selectInput' -import { clearToasts } from './clearToasts' import { clickIfEnabledAndWait } from './click' import { navigateToConfig } from './navigate' @@ -67,7 +66,6 @@ export async function configResetAllSettings({ page }: { page: Page }) { page.getByText('Save changes'), page.getByText('Settings have been saved') ) - await clearToasts({ page }) await setViewMode({ page, state: 'basic' }) await navigateToConfig({ page }) } diff --git a/apps/renterd-e2e/src/fixtures/buckets.ts b/apps/renterd-e2e/src/fixtures/buckets.ts index efa145d4f..5e0ae676f 100644 --- a/apps/renterd-e2e/src/fixtures/buckets.ts +++ b/apps/renterd-e2e/src/fixtures/buckets.ts @@ -1,7 +1,6 @@ import { Page, expect } from '@playwright/test' import { navigateToBuckets } from './navigate' import { fillTextInputByName } from './textInput' -import { clearToasts } from './clearToasts' import { deleteDirectory, deleteFile } from './files' export async function createBucket(page: Page, name: string) { @@ -11,7 +10,6 @@ export async function createBucket(page: Page, name: string) { await page.locator('input[name=name]').press('Enter') await expect(page.getByRole('dialog')).toBeHidden() await expect(page.getByText('Bucket created')).toBeVisible() - await clearToasts({ page }) await expect(page.getByRole('cell', { name })).toBeVisible() } diff --git a/apps/renterd-e2e/src/fixtures/click.ts b/apps/renterd-e2e/src/fixtures/click.ts index 018421aa9..b6eac81d8 100644 --- a/apps/renterd-e2e/src/fixtures/click.ts +++ b/apps/renterd-e2e/src/fixtures/click.ts @@ -33,3 +33,8 @@ export async function clickIf( } return false } + +export async function clickTwice(locator: Locator) { + await locator.click() + await locator.click() +} diff --git a/apps/renterd-e2e/src/fixtures/configResetAllSettings.ts b/apps/renterd-e2e/src/fixtures/configResetAllSettings.ts index b1b3a4fde..49fb42a7b 100644 --- a/apps/renterd-e2e/src/fixtures/configResetAllSettings.ts +++ b/apps/renterd-e2e/src/fixtures/configResetAllSettings.ts @@ -2,7 +2,6 @@ import { Page } from '@playwright/test' import { setSwitchByLabel } from './switchValue' import { setViewMode } from './configViewMode' import { fillTextInputByName } from './textInput' -import { clearToasts } from './clearToasts' import { clickIfEnabledAndWait } from './click' import { fillSelectInputByName } from './selectInput' import { navigateToConfig } from './navigate' @@ -73,6 +72,5 @@ export async function configResetAllSettings({ page }: { page: Page }) { page.getByText('Save changes'), page.getByText('Configuration has been saved') ) - await clearToasts({ page }) await setViewMode({ page, state: 'basic' }) } diff --git a/apps/renterd-e2e/src/fixtures/preferences.ts b/apps/renterd-e2e/src/fixtures/preferences.ts index 8bd7dbcaf..830ea20ee 100644 --- a/apps/renterd-e2e/src/fixtures/preferences.ts +++ b/apps/renterd-e2e/src/fixtures/preferences.ts @@ -1,11 +1,16 @@ import { Page } from 'playwright' import { fillSelectInputByName } from './selectInput' +import { CurrencyId } from '@siafoundation/react-core' export async function setCurrencyDisplay( page: Page, - display: 'sc' | 'fiat' | 'bothPreferSc' | 'bothPreferFiat' + display: 'sc' | 'fiat' | 'bothPreferSc' | 'bothPreferFiat', + currency?: CurrencyId ) { - await page.getByLabel('App preferences').click() + await page.getByTestId('sidenav').getByLabel('App preferences').click() await fillSelectInputByName(page, 'currencyDisplay', display) + if (currency) { + await fillSelectInputByName(page, 'currencyFiat', currency) + } await page.getByRole('dialog').getByLabel('close').click() } diff --git a/apps/renterd-e2e/src/fixtures/siascan.ts b/apps/renterd-e2e/src/fixtures/siascan.ts index 3f3349161..5a6225193 100644 --- a/apps/renterd-e2e/src/fixtures/siascan.ts +++ b/apps/renterd-e2e/src/fixtures/siascan.ts @@ -4,7 +4,26 @@ export async function mockApiSiaScanExchangeRates({ page }: { page: Page }) { await page.route( 'https://api.siascan.com/exchange-rate/siacoin/*', async (route) => { - await route.fulfill({ json: 0.003944045283 }) + if (route.request().url().endsWith('jpy')) { + await route.fulfill({ json: 0.727779694168 }) + } else { + await route.fulfill({ json: 0.003944045283 }) + } + } + ) +} + +export async function mockApiSiaScanExchangeRatesHanging({ + page, +}: { + page: Page +}) { + await page.route( + 'https://api.siascan.com/exchange-rate/siacoin/*', + async () => { + await new Promise(() => { + // Never resolve, leaving the request hanging. + }) } ) } diff --git a/apps/renterd-e2e/src/specs/config.spec.ts b/apps/renterd-e2e/src/specs/config.spec.ts index 7ded3bbc8..d00ebe474 100644 --- a/apps/renterd-e2e/src/specs/config.spec.ts +++ b/apps/renterd-e2e/src/specs/config.spec.ts @@ -10,6 +10,7 @@ import { afterTest, beforeTest } from '../fixtures/beforeTest' import { setCurrencyDisplay } from '../fixtures/preferences' import { configResetAllSettings } from '../fixtures/configResetAllSettings' import { fillSelectInputByName } from '../fixtures/selectInput' +import { clickTwice } from '../fixtures/click' test.beforeEach(async ({ page }) => { await beforeTest(page) @@ -20,7 +21,7 @@ test.afterEach(async () => { await afterTest() }) -test('basic field change and save behaviour', async ({ page }) => { +test('field change and save behaviours', async ({ page }) => { // Reset state. await navigateToConfig({ page }) await setViewMode({ page, state: 'basic' }) @@ -62,33 +63,6 @@ test('basic field change and save behaviour', async ({ page }) => { for (const part of estimateParts) { await expect(page.getByText(part)).toBeVisible() } - - // Tips are displayed in the correct currency. - await expect( - page - .getByTestId('maxStoragePriceTBMonthGroup') - .getByLabel('Network average') - .getByText('341') - ).toBeVisible() - await expect( - page - .getByTestId('maxStoragePriceTBMonthGroup') - .getByLabel('Fit current allowance') - .getByText('300') - ).toBeVisible() - await setCurrencyDisplay(page, 'bothPreferFiat') - await expect( - page - .getByTestId('maxStoragePriceTBMonthGroup') - .getByLabel('Network average') - .getByText('$1.34') - ).toBeVisible() - await expect( - page - .getByTestId('maxStoragePriceTBMonthGroup') - .getByLabel('Fit current allowance') - .getByText('$1.18') - ).toBeVisible() }) test('set max prices to fit current allowance', async ({ page }) => { @@ -243,11 +217,11 @@ test('set max prices via individual field tips', async ({ page }) => { await expect( page.getByText('Current pricing may not fit allowance') ).toBeVisible() - await page + const fitButton = page .getByTestId('maxStoragePriceTBMonthGroup') .getByLabel('Fit current allowance') - .click() // TODO: remove the need to click twice, there is some sort of glitch after toggling the pinning switch. + await clickTwice(fitButton) await page .getByTestId('maxStoragePriceTBMonthGroup') .getByLabel('Fit current allowance') @@ -273,3 +247,27 @@ test('set max prices via individual field tips', async ({ page }) => { await expectTextInputByName(page, 'maxUploadPriceTBPinned', '$0.88') await expectTextInputByName(page, 'maxDownloadPriceTB', '1,118.588756') }) + +test('pinned currency and app display currency can be different', async ({ + page, +}) => { + await navigateToConfig({ page }) + await setViewMode({ page, state: 'basic' }) + await fillSelectInputByName(page, 'pinnedCurrency', 'usd') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + await setSwitchByLabel(page, 'shouldPinMaxStoragePrice', true) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$5') + await expect( + page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('¥248.17') + ).toBeVisible() + const averageButton = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('¥248.17') + // TODO: remove the need to click twice, there is some sort of glitch after toggling the pinning switch. + await clickTwice(averageButton) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$1.34') +}) diff --git a/apps/renterd-e2e/src/specs/configTips.spec.ts b/apps/renterd-e2e/src/specs/configTips.spec.ts new file mode 100644 index 000000000..14ceba047 --- /dev/null +++ b/apps/renterd-e2e/src/specs/configTips.spec.ts @@ -0,0 +1,416 @@ +import { test, expect } from '@playwright/test' +import { setSwitchByLabel } from '../fixtures/switchValue' +import { setViewMode } from '../fixtures/configViewMode' +import { navigateToConfig } from '../fixtures/navigate' +import { + expectTextInputByName, + fillTextInputByName, +} from '../fixtures/textInput' +import { afterTest, beforeTest } from '../fixtures/beforeTest' +import { setCurrencyDisplay } from '../fixtures/preferences' +import { clickTwice } from '../fixtures/click' + +test.beforeEach(async ({ page }) => { + await beforeTest(page) +}) + +test.afterEach(async () => { + await afterTest() +}) + +test('field tips for storage', async ({ page }) => { + await navigateToConfig({ page }) + await setViewMode({ page, state: 'advanced' }) + + await fillTextInputByName(page, 'allowanceMonth', '7000') + await fillTextInputByName(page, 'storageTB', '7') + await fillTextInputByName(page, 'uploadTBMonth', '7') + await fillTextInputByName(page, 'downloadTBMonth', '7') + await fillTextInputByName(page, 'minShards', '1') + await fillTextInputByName(page, 'totalShards', '3') + + // Storage siacoin. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + let storageNetworkAverage = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('341') + await expect(storageNetworkAverage).toBeVisible() + await clickTwice(storageNetworkAverage) + await expectTextInputByName(page, 'maxStoragePriceTBMonth', '341') + let storageFitCurrentAllowance = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Fit current allowance') + .getByText('300') + await expect(storageFitCurrentAllowance).toBeVisible() + await clickTwice(storageFitCurrentAllowance) + await expectTextInputByName(page, 'maxStoragePriceTBMonth', '300') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + let storageNetworkAverageFiat = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('$1.34') + await expect(storageNetworkAverageFiat).toBeVisible() + await clickTwice(storageNetworkAverageFiat) + await expectTextInputByName(page, 'maxStoragePriceTBMonth', '341') + let storageFitCurrentAllowanceFiat = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Fit current allowance') + .getByText('$1.18') + await expect(storageFitCurrentAllowanceFiat).toBeVisible() + await clickTwice(storageFitCurrentAllowanceFiat) + await expectTextInputByName(page, 'maxStoragePriceTBMonth', '300') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + let storageNetworkAverageFiatJPY = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('¥248.17') + await expect(storageNetworkAverageFiatJPY).toBeVisible() + await clickTwice(storageNetworkAverageFiatJPY) + await expectTextInputByName(page, 'maxStoragePriceTBMonth', '341') + let storageFitCurrentAllowanceFiatJPY = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Fit current allowance') + .getByText('¥218.33') + await expect(storageFitCurrentAllowanceFiatJPY).toBeVisible() + await clickTwice(storageFitCurrentAllowanceFiatJPY) + await expectTextInputByName(page, 'maxStoragePriceTBMonth', '300') + + // Fiat. + await setSwitchByLabel(page, 'shouldPinAllowance', true) + await setSwitchByLabel(page, 'shouldPinMaxStoragePrice', true) + await fillTextInputByName(page, 'allowanceMonthPinned', '30') + + // Storage fiat. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + storageNetworkAverage = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('341') + await expect(storageNetworkAverage).toBeVisible() + await clickTwice(storageNetworkAverage) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$1.34') + storageFitCurrentAllowance = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Fit current allowance') + .getByText('326') + await expect(storageFitCurrentAllowance).toBeVisible() + await clickTwice(storageFitCurrentAllowance) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$1.29') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + storageNetworkAverageFiat = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('$1.34') + await expect(storageNetworkAverageFiat).toBeVisible() + await clickTwice(storageNetworkAverageFiat) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$1.34') + storageFitCurrentAllowanceFiat = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Fit current allowance') + .getByText('$1.29') + await expect(storageFitCurrentAllowanceFiat).toBeVisible() + await clickTwice(storageFitCurrentAllowanceFiat) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$1.29') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + storageNetworkAverageFiatJPY = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('¥248.17') + await expect(storageNetworkAverageFiatJPY).toBeVisible() + await clickTwice(storageNetworkAverageFiatJPY) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$1.34') + storageFitCurrentAllowanceFiatJPY = page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Fit current allowance') + .getByText('¥237.25') + await expect(storageFitCurrentAllowanceFiatJPY).toBeVisible() + await clickTwice(storageFitCurrentAllowanceFiatJPY) + await expectTextInputByName(page, 'maxStoragePriceTBMonthPinned', '$1.29') +}) + +test('field tips for upload', async ({ page }) => { + await navigateToConfig({ page }) + await setViewMode({ page, state: 'advanced' }) + + await fillTextInputByName(page, 'allowanceMonth', '7000') + await fillTextInputByName(page, 'storageTB', '7') + await fillTextInputByName(page, 'uploadTBMonth', '7') + await fillTextInputByName(page, 'downloadTBMonth', '7') + await fillTextInputByName(page, 'minShards', '1') + await fillTextInputByName(page, 'totalShards', '3') + + // Upload siacoin. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + let uploadNetworkAverage = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('76') + await expect(uploadNetworkAverage).toBeVisible() + await clickTwice(uploadNetworkAverage) + await expectTextInputByName(page, 'maxUploadPriceTB', '76') + let uploadFitCurrentAllowance = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('75') + await expect(uploadFitCurrentAllowance).toBeVisible() + await clickTwice(uploadFitCurrentAllowance) + await expectTextInputByName(page, 'maxUploadPriceTB', '75') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + let uploadNetworkAverageFiat = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('$0.30') + await expect(uploadNetworkAverageFiat).toBeVisible() + await clickTwice(uploadNetworkAverageFiat) + await expectTextInputByName(page, 'maxUploadPriceTB', '76') + let uploadFitCurrentAllowanceFiat = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('$0.30') + await expect(uploadFitCurrentAllowanceFiat).toBeVisible() + await clickTwice(uploadFitCurrentAllowanceFiat) + await expectTextInputByName(page, 'maxUploadPriceTB', '75') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + let uploadNetworkAverageFiatJPY = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('¥55.31') + await expect(uploadNetworkAverageFiatJPY).toBeVisible() + await clickTwice(uploadNetworkAverageFiatJPY) + await expectTextInputByName(page, 'maxUploadPriceTB', '76') + let uploadFitCurrentAllowanceFiatJPY = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('¥54.58') + await expect(uploadFitCurrentAllowanceFiatJPY).toBeVisible() + await clickTwice(uploadFitCurrentAllowanceFiatJPY) + await expectTextInputByName(page, 'maxUploadPriceTB', '75') + + // Fiat. + await setSwitchByLabel(page, 'shouldPinAllowance', true) + await setSwitchByLabel(page, 'shouldPinMaxUploadPrice', true) + await fillTextInputByName(page, 'allowanceMonthPinned', '30') + + // Upload fiat. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + uploadNetworkAverage = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('76') + await expect(uploadNetworkAverage).toBeVisible() + await clickTwice(uploadNetworkAverage) + await expectTextInputByName(page, 'maxUploadPriceTBPinned', '$0.30') + uploadFitCurrentAllowance = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('81') + await expect(uploadFitCurrentAllowance).toBeVisible() + await clickTwice(uploadFitCurrentAllowance) + await expectTextInputByName(page, 'maxUploadPriceTBPinned', '$0.32') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + uploadNetworkAverageFiat = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('$0.30') + await expect(uploadNetworkAverageFiat).toBeVisible() + await clickTwice(uploadNetworkAverageFiat) + await expectTextInputByName(page, 'maxUploadPriceTBPinned', '$0.30') + uploadFitCurrentAllowanceFiat = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('$0.32') + await expect(uploadFitCurrentAllowanceFiat).toBeVisible() + await clickTwice(uploadFitCurrentAllowanceFiat) + await expectTextInputByName(page, 'maxUploadPriceTBPinned', '$0.32') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + uploadNetworkAverageFiatJPY = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('¥55.31') + await expect(uploadNetworkAverageFiatJPY).toBeVisible() + await clickTwice(uploadNetworkAverageFiatJPY) + await expectTextInputByName(page, 'maxUploadPriceTBPinned', '$0.30') + uploadFitCurrentAllowanceFiatJPY = page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('¥59.31') + await expect(uploadFitCurrentAllowanceFiatJPY).toBeVisible() + await clickTwice(uploadFitCurrentAllowanceFiatJPY) + await expectTextInputByName(page, 'maxUploadPriceTBPinned', '$0.32') +}) + +test('field tips for download', async ({ page }) => { + await navigateToConfig({ page }) + await setViewMode({ page, state: 'advanced' }) + + await fillTextInputByName(page, 'allowanceMonth', '7000') + await fillTextInputByName(page, 'storageTB', '7') + await fillTextInputByName(page, 'uploadTBMonth', '7') + await fillTextInputByName(page, 'downloadTBMonth', '7') + await fillTextInputByName(page, 'minShards', '1') + await fillTextInputByName(page, 'totalShards', '3') + + // Download siacoin. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + let downloadNetworkAverage = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('899') + await expect(downloadNetworkAverage).toBeVisible() + await clickTwice(downloadNetworkAverage) + await expectTextInputByName(page, 'maxDownloadPriceTB', '899') + let downloadFitCurrentAllowance = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('375') + await expect(downloadFitCurrentAllowance).toBeVisible() + await clickTwice(downloadFitCurrentAllowance) + await expectTextInputByName(page, 'maxDownloadPriceTB', '375') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + let downloadNetworkAverageFiat = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('$3.55') + await expect(downloadNetworkAverageFiat).toBeVisible() + await clickTwice(downloadNetworkAverageFiat) + await expectTextInputByName(page, 'maxDownloadPriceTB', '899') + let downloadFitCurrentAllowanceFiat = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('$1.48') + await expect(downloadFitCurrentAllowanceFiat).toBeVisible() + await clickTwice(downloadFitCurrentAllowanceFiat) + await expectTextInputByName(page, 'maxDownloadPriceTB', '375') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + let downloadNetworkAverageFiatJPY = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('¥654.27') + await expect(downloadNetworkAverageFiatJPY).toBeVisible() + await clickTwice(downloadNetworkAverageFiatJPY) + await expectTextInputByName(page, 'maxDownloadPriceTB', '899') + let downloadFitCurrentAllowanceFiatJPY = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('¥272.92') + await expect(downloadFitCurrentAllowanceFiatJPY).toBeVisible() + await clickTwice(downloadFitCurrentAllowanceFiatJPY) + await expectTextInputByName(page, 'maxDownloadPriceTB', '375') + + // Fiat. + await setSwitchByLabel(page, 'shouldPinAllowance', true) + await setSwitchByLabel(page, 'shouldPinMaxDownloadPrice', true) + await fillTextInputByName(page, 'allowanceMonthPinned', '30') + + // Download fiat. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + downloadNetworkAverage = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('899') + await expect(downloadNetworkAverage).toBeVisible() + await clickTwice(downloadNetworkAverage) + await expectTextInputByName(page, 'maxDownloadPriceTBPinned', '$3.55') + downloadFitCurrentAllowance = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('407') + await expect(downloadFitCurrentAllowance).toBeVisible() + await clickTwice(downloadFitCurrentAllowance) + await expectTextInputByName(page, 'maxDownloadPriceTBPinned', '$1.61') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + downloadNetworkAverageFiat = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('$3.55') + await expect(downloadNetworkAverageFiat).toBeVisible() + await clickTwice(downloadNetworkAverageFiat) + await expectTextInputByName(page, 'maxDownloadPriceTBPinned', '$3.55') + downloadFitCurrentAllowanceFiat = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('$1.61') + await expect(downloadFitCurrentAllowanceFiat).toBeVisible() + await clickTwice(downloadFitCurrentAllowanceFiat) + await expectTextInputByName(page, 'maxDownloadPriceTBPinned', '$1.61') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + downloadNetworkAverageFiatJPY = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('¥654.27') + await expect(downloadNetworkAverageFiatJPY).toBeVisible() + await clickTwice(downloadNetworkAverageFiatJPY) + await expectTextInputByName(page, 'maxDownloadPriceTBPinned', '$3.55') + downloadFitCurrentAllowanceFiatJPY = page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Fit current allowance') + .getByText('¥296.56') + await expect(downloadFitCurrentAllowanceFiatJPY).toBeVisible() + await clickTwice(downloadFitCurrentAllowanceFiatJPY) + await expectTextInputByName(page, 'maxDownloadPriceTBPinned', '$1.61') +}) + +test('field tips max contract and rpc prices', async ({ page }) => { + await navigateToConfig({ page }) + await setViewMode({ page, state: 'advanced' }) + + await fillTextInputByName(page, 'allowanceMonth', '7000') + await fillTextInputByName(page, 'storageTB', '7') + await fillTextInputByName(page, 'uploadTBMonth', '7') + await fillTextInputByName(page, 'downloadTBMonth', '7') + await fillTextInputByName(page, 'minShards', '1') + await fillTextInputByName(page, 'totalShards', '3') + + // Contract. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + const contractSuggestion = page + .getByTestId('maxContractPrice') + .getByLabel('suggestion') + .getByText('1') + await expect(contractSuggestion).toBeVisible() + await clickTwice(contractSuggestion) + await expectTextInputByName(page, 'maxContractPrice', '1') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + const contractSuggestionFiat = page + .getByTestId('maxContractPrice') + .getByLabel('suggestion') + .getByText('$0.00') + await expect(contractSuggestionFiat).toBeVisible() + await clickTwice(contractSuggestionFiat) + await expectTextInputByName(page, 'maxContractPrice', '1') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + const contractSuggestionFiatJPY = page + .getByTestId('maxContractPrice') + .getByLabel('suggestion') + .getByText('¥0.73') + await expect(contractSuggestionFiatJPY).toBeVisible() + await clickTwice(contractSuggestionFiatJPY) + await expectTextInputByName(page, 'maxContractPrice', '1') + + // RPC. + await setCurrencyDisplay(page, 'bothPreferSc', 'usd') + const rpcSuggestion = page + .getByTestId('maxRPCPriceMillion') + .getByLabel('suggestion') + .getByText('10') + await expect(rpcSuggestion).toBeVisible() + await clickTwice(rpcSuggestion) + await expectTextInputByName(page, 'maxRPCPriceMillion', '10') + await setCurrencyDisplay(page, 'bothPreferFiat', 'usd') + const rpcSuggestionFiat = page + .getByTestId('maxRPCPriceMillion') + .getByLabel('suggestion') + .getByText('$0.04') + await expect(rpcSuggestionFiat).toBeVisible() + await clickTwice(rpcSuggestionFiat) + await expectTextInputByName(page, 'maxRPCPriceMillion', '10') + await setCurrencyDisplay(page, 'bothPreferFiat', 'jpy') + const rpcSuggestionFiatJPY = page + .getByTestId('maxRPCPriceMillion') + .getByLabel('suggestion') + .getByText('¥7.28') + await expect(rpcSuggestionFiatJPY).toBeVisible() + await clickTwice(rpcSuggestionFiatJPY) + await expectTextInputByName(page, 'maxRPCPriceMillion', '10') +}) diff --git a/apps/renterd-e2e/src/specs/externalData.spec.ts b/apps/renterd-e2e/src/specs/externalData.spec.ts new file mode 100644 index 000000000..60c1ebb33 --- /dev/null +++ b/apps/renterd-e2e/src/specs/externalData.spec.ts @@ -0,0 +1,167 @@ +import { test, expect } from '@playwright/test' +import { setSwitchByLabel } from '../fixtures/switchValue' +import { setViewMode } from '../fixtures/configViewMode' +import { navigateToConfig } from '../fixtures/navigate' +import { afterTest } from '../fixtures/beforeTest' +import { mockApiSiaScanExchangeRatesHanging } from '../fixtures/siascan' +import { clusterd, setupCluster } from '@siafoundation/clusterd' +import { login } from '../fixtures/login' +import { fillSelectInputByName } from '../fixtures/selectInput' +import { + mockApiSiaCentralHostsNetworkAverages, + mockApiSiaCentralHostsNetworkAveragesHanging, +} from '@siafoundation/sia-central-mock' + +test.beforeEach(async () => { + await setupCluster({ renterdCount: 1 }) +}) + +test.afterEach(async () => { + await afterTest() +}) + +test('configuration shows not-enabled message when exchange rates API hangs', async ({ + page, +}) => { + await mockApiSiaScanExchangeRatesHanging({ page }) + const renterdNode = clusterd.nodes.find((n) => n.type === 'renterd') + await login({ + page, + address: renterdNode.apiAddress, + password: renterdNode.password, + }) + await navigateToConfig({ page }) + await setViewMode({ page, state: 'basic' }) + await setSwitchByLabel(page, 'shouldPinAllowance', true) + await setSwitchByLabel(page, 'shouldPinMaxStoragePrice', true) + await setSwitchByLabel(page, 'shouldPinMaxUploadPrice', true) + + await fillSelectInputByName(page, 'pinnedCurrency', 'usd') + + await expect( + page + .getByTestId('allowanceMonthGroup') + .getByText('Enable an exchange rate API') + ).toBeVisible() + await expect( + page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByText('Enable an exchange rate API') + ).toBeVisible() + await expect( + page + .getByTestId('maxUploadPriceTBGroup') + .getByText('Enable an exchange rate API') + ).toBeVisible() +}) + +test('configuration does not show network averages when sia central API hangs', async ({ + page, +}) => { + await mockApiSiaCentralHostsNetworkAveragesHanging({ page }) + const renterdNode = clusterd.nodes.find((n) => n.type === 'renterd') + await login({ + page, + address: renterdNode.apiAddress, + password: renterdNode.password, + }) + await navigateToConfig({ page }) + await setViewMode({ page, state: 'basic' }) + await fillSelectInputByName(page, 'pinnedCurrency', 'usd') + + // Network averages should NOT be shown. + await setSwitchByLabel(page, 'shouldPinMaxStoragePrice', false) + await setSwitchByLabel(page, 'shouldPinMaxUploadPrice', false) + await setSwitchByLabel(page, 'shouldPinMaxDownloadPrice', false) + await expect( + page.getByTestId('maxStoragePriceTBMonthGroup').getByText('Network average') + ).toBeHidden() + await expect( + page.getByTestId('maxUploadPriceTBGroup').getByText('Network average') + ).toBeHidden() + await expect( + page.getByTestId('maxDownloadPriceTBGroup').getByText('Network average') + ).toBeHidden() + await setSwitchByLabel(page, 'shouldPinMaxStoragePrice', true) + await setSwitchByLabel(page, 'shouldPinMaxUploadPrice', true) + await setSwitchByLabel(page, 'shouldPinMaxDownloadPrice', true) + await expect( + page.getByTestId('maxStoragePriceTBMonthGroup').getByText('Network average') + ).toBeHidden() + await expect( + page.getByTestId('maxUploadPriceTBGroup').getByText('Network average') + ).toBeHidden() + await expect( + page.getByTestId('maxDownloadPriceTBGroup').getByText('Network average') + ).toBeHidden() + + await page.unroute('https://api.siascan.com/exchange-rate/siacoin/*') + await mockApiSiaCentralHostsNetworkAverages({ page }) + await page.reload() + + // Network averages should be shown, and not be 0. + await setSwitchByLabel(page, 'shouldPinMaxStoragePrice', false) + await setSwitchByLabel(page, 'shouldPinMaxUploadPrice', false) + await setSwitchByLabel(page, 'shouldPinMaxDownloadPrice', false) + await expect( + page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + ).toBeVisible() + await expect( + page.getByTestId('maxUploadPriceTBGroup').getByLabel('Network average') + ).toBeVisible() + await expect( + page.getByTestId('maxDownloadPriceTBGroup').getByLabel('Network average') + ).toBeVisible() + await expect( + page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('0 SC') + ).toBeHidden() + await expect( + page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('0 SC') + ).toBeHidden() + await expect( + page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('0 SC') + ).toBeHidden() + await setSwitchByLabel(page, 'shouldPinMaxStoragePrice', true) + await setSwitchByLabel(page, 'shouldPinMaxUploadPrice', true) + await setSwitchByLabel(page, 'shouldPinMaxDownloadPrice', true) + await expect( + page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + ).toBeVisible() + await expect( + page.getByTestId('maxUploadPriceTBGroup').getByLabel('Network average') + ).toBeVisible() + await expect( + page.getByTestId('maxDownloadPriceTBGroup').getByLabel('Network average') + ).toBeVisible() + await expect( + page + .getByTestId('maxStoragePriceTBMonthGroup') + .getByLabel('Network average') + .getByText('0 SC') + ).toBeHidden() + await expect( + page + .getByTestId('maxUploadPriceTBGroup') + .getByLabel('Network average') + .getByText('0 SC') + ).toBeHidden() + await expect( + page + .getByTestId('maxDownloadPriceTBGroup') + .getByLabel('Network average') + .getByText('0 SC') + ).toBeHidden() +}) diff --git a/apps/renterd-e2e/src/specs/files.spec.ts b/apps/renterd-e2e/src/specs/files.spec.ts index bc85fde32..de753002c 100644 --- a/apps/renterd-e2e/src/specs/files.spec.ts +++ b/apps/renterd-e2e/src/specs/files.spec.ts @@ -15,7 +15,6 @@ import { createDirectory, } from '../fixtures/files' import { fillTextInputByName } from '../fixtures/textInput' -import { clearToasts } from '../fixtures/clearToasts' import { afterTest, beforeTest } from '../fixtures/beforeTest' test.beforeEach(async ({ page }) => { @@ -80,7 +79,6 @@ test('can create directory, upload file, rename file, navigate, delete a file, d await expect( page.getByText('The current directory does not contain any files yet') ).toBeVisible() - await clearToasts({ page }) // Upload. await dragAndDropFile( @@ -103,7 +101,6 @@ test('can create directory, upload file, rename file, navigate, delete a file, d // Delete file. await deleteFile(page, newFilePath) await fileNotInList(page, newFilePath) - await clearToasts({ page }) // Upload the file again. await dragAndDropFile( @@ -153,7 +150,6 @@ test('shows a new intermediate directory when uploading nested files', async ({ await expect( page.getByText('The current directory does not contain any files yet') ).toBeVisible() - await clearToasts({ page }) // Upload a nested file. await dragAndDropFile( diff --git a/apps/renterd-e2e/src/specs/recommendations.spec.ts b/apps/renterd-e2e/src/specs/recommendations.spec.ts index 3d25f114b..572e6eddc 100644 --- a/apps/renterd-e2e/src/specs/recommendations.spec.ts +++ b/apps/renterd-e2e/src/specs/recommendations.spec.ts @@ -3,7 +3,6 @@ import { setSwitchByLabel } from '../fixtures/switchValue' import { setViewMode } from '../fixtures/configViewMode' import { navigateToConfig } from '../fixtures/navigate' import { fillTextInputByName } from '../fixtures/textInput' -import { clearToasts } from '../fixtures/clearToasts' import { clickIfEnabledAndWait, clickIf } from '../fixtures/click' import { afterTest, beforeTest } from '../fixtures/beforeTest' import { configResetAllSettings } from '../fixtures/configResetAllSettings' @@ -35,7 +34,6 @@ test('system offers recommendations', async ({ page }) => { page.getByText('Save changes'), page.getByText('Configuration has been saved') ) - await clearToasts({ page }) // Configuration matches with hosts. await expect( @@ -56,7 +54,6 @@ test('system offers recommendations', async ({ page }) => { page.getByText('Save changes'), page.getByText('Configuration has been saved') ) - await clearToasts({ page }) // There are now recommendations. await expect( page.getByText('No recommendations to match with more hosts') diff --git a/apps/renterd/contexts/config/fieldTips/MaxContractPrice.tsx b/apps/renterd/contexts/config/fieldTips/MaxContractPrice.tsx new file mode 100644 index 000000000..413c3e5a4 --- /dev/null +++ b/apps/renterd/contexts/config/fieldTips/MaxContractPrice.tsx @@ -0,0 +1,45 @@ +import { + ConfigFields, + TipNumber, + formSetField, +} from '@siafoundation/design-system' +import React from 'react' +import { Categories, RecommendationItem, InputValues } from '../types' +import { toHastings } from '@siafoundation/units' +import { UseFormReturn } from 'react-hook-form' +import { recommendationTipContent } from './Tip' + +export function MaxContractPriceTips({ + form, + fields, + recommendations, +}: { + form: UseFormReturn + fields: ConfigFields + recommendations: Partial> +}) { + const recommendationPrice = recommendations?.maxContractPrice?.targetValue + + return ( + <> + {recommendationPrice && ( + + formSetField({ + form, + fields, + name: 'maxContractPrice', + value: recommendationPrice, + options: true, + }) + } + /> + )} + + ) +} diff --git a/apps/renterd/contexts/config/fieldTips/MaxDownloadPrice.tsx b/apps/renterd/contexts/config/fieldTips/MaxDownloadPrice.tsx index de11d9625..4eaec1c86 100644 --- a/apps/renterd/contexts/config/fieldTips/MaxDownloadPrice.tsx +++ b/apps/renterd/contexts/config/fieldTips/MaxDownloadPrice.tsx @@ -12,6 +12,7 @@ import { fitPriceToCurrentAllowanceTipContent, recommendationTipContent, } from './Tip' +import { useAverages } from '../useAverages' export function MaxDownloadPriceTips({ form, @@ -22,6 +23,7 @@ export function MaxDownloadPriceTips({ fields: ConfigFields recommendations: Partial> }) { + const { downloadAverage } = useAverages() const derived = useAllowanceDerivedPricingForEnabledFields({ form, }) @@ -29,6 +31,24 @@ export function MaxDownloadPriceTips({ return ( <> + {downloadAverage && ( + { + formSetField({ + form, + fields, + name: 'maxDownloadPriceTB', + value: downloadAverage, + options: true, + }) + }} + /> + )} {derived?.maxDownloadPriceTB && ( + {downloadAverage && rate && ( + { + formSetField({ + form, + fields, + name: 'maxDownloadPriceTBPinned', + value: downloadAverage.times(rate), + options: true, + }) + }} + /> + )} {derivedPriceInSiacoin && derived?.maxDownloadPriceTBPinned && ( - formSetField({ - form, - fields, - name: 'maxRPCPriceMillion', - value: recommendationPrice, - options: true, - }) - } - /> - ) + <> + {recommendationPrice && ( + + formSetField({ + form, + fields, + name: 'maxRPCPriceMillion', + value: recommendationPrice, + options: true, + }) + } + /> + )} + ) } diff --git a/apps/renterd/contexts/config/fieldTips/MaxStoragePrice.tsx b/apps/renterd/contexts/config/fieldTips/MaxStoragePrice.tsx index 696a261cf..8ddc22d20 100644 --- a/apps/renterd/contexts/config/fieldTips/MaxStoragePrice.tsx +++ b/apps/renterd/contexts/config/fieldTips/MaxStoragePrice.tsx @@ -13,6 +13,7 @@ import { fitPriceToCurrentAllowanceTipContent, recommendationTipContent, } from './Tip' +import { useAverages } from '../useAverages' export function MaxStoragePriceTips({ form, @@ -23,6 +24,7 @@ export function MaxStoragePriceTips({ fields: ConfigFields recommendations: Partial> }) { + const { storageAverage } = useAverages() const derived = useAllowanceDerivedPricingForEnabledFields({ form, }) @@ -32,6 +34,24 @@ export function MaxStoragePriceTips({ return ( <> + {storageAverage && ( + { + formSetField({ + form, + fields, + name: 'maxStoragePriceTBMonth', + value: storageAverage, + options: true, + }) + }} + /> + )} {derived?.maxStoragePriceTBMonth && ( + {storageAverage && rate && ( + { + formSetField({ + form, + fields, + name: 'maxStoragePriceTBMonthPinned', + value: storageAverage.times(rate), + options: true, + }) + }} + /> + )} {derivedPriceInSiacoin && derived?.maxStoragePriceTBMonthPinned && ( recommendations: Partial> }) { + const { uploadAverage } = useAverages() const derived = useAllowanceDerivedPricingForEnabledFields({ form, }) @@ -31,6 +33,24 @@ export function MaxUploadPriceTips({ return ( <> + {uploadAverage && ( + { + formSetField({ + form, + fields, + name: 'maxUploadPriceTB', + value: uploadAverage, + options: true, + }) + }} + /> + )} {derived?.maxUploadPriceTB && ( recommendations: Partial> }) { + const { rate } = useFormExchangeRate(form) + const { uploadAverage } = useAverages() const derived = useAllowanceDerivedPricingForEnabledFields({ form, }) - const { rate } = useFormExchangeRate(form) const maxUploadPriceTBPinned = form.watch('maxUploadPriceTBPinned') const currentPriceInSiacoin = maxUploadPriceTBPinned && rate @@ -106,6 +127,24 @@ export function MaxUploadPricePinnedTips({ : undefined return ( <> + {uploadAverage && rate && ( + { + formSetField({ + form, + fields, + name: 'maxUploadPriceTBPinned', + value: uploadAverage.times(rate), + options: true, + }) + }} + /> + )} {derivedPriceInSiacoin && derived?.maxUploadPriceTBPinned && ( > @@ -62,8 +49,6 @@ export type Fields = ReturnType export function getFields({ advancedDefaults, - averagesSc, - averagesFiat, recommendations, isAutopilotEnabled, configViewMode, @@ -435,8 +420,6 @@ export function getFields({ ), units: 'SC/TB/month', - average: averagesSc?.storageAverage, - averageTip: 'Averages provided by Sia Central.', decimalsLimitSc: scDecimalPlaces, validation: { required: 'required', @@ -455,8 +438,6 @@ export function getFields({ units: '/TB/month', type: 'fiat', category: 'gouging', - average: averagesFiat?.storageAverage, - averageTip: 'Averages provided by Sia Central.', validation: { validate: { required: requiredIfPinningEnabled( @@ -509,8 +490,6 @@ export function getFields({ ), units: 'SC/TB', - average: averagesSc?.uploadAverage, - averageTip: 'Averages provided by Sia Central.', decimalsLimitSc: scDecimalPlaces, validation: { required: 'required', @@ -528,8 +507,6 @@ export function getFields({ description: '', units: '/TB', type: 'fiat', - average: averagesFiat?.uploadAverage, - averageTip: 'Averages provided by Sia Central.', category: 'gouging', validation: { validate: { @@ -583,8 +560,6 @@ export function getFields({ ), units: 'SC/TB', - average: averagesSc?.downloadAverage, - averageTip: `Averages provided by Sia Central.`, decimalsLimitSc: scDecimalPlaces, validation: { required: 'required', @@ -602,8 +577,6 @@ export function getFields({ description: '', units: '/TB', type: 'fiat', - average: averagesFiat?.downloadAverage, - averageTip: `Averages provided by Sia Central.`, category: 'gouging', validation: { validate: { @@ -643,37 +616,37 @@ export function getFields({ type: 'siacoin', title: 'Max contract price', description: <>The max allowed price to form a contract., - average: averagesSc?.contractAverage, - averageTip: `Averages provided by Sia Central.`, + suggestion: new BigNumber(1), + suggestionTip: 'The suggested value is 1 SC.', decimalsLimitSc: scDecimalPlaces, - tipsDecimalsLimitSc: 3, + tipsDecimalsLimitSc: 0, hidden: configViewMode === 'basic', - suggestionLabel: 'Match with more hosts', - suggestion: recommendations.maxContractPrice?.targetValue, - suggestionTip: 'This value will help you match with more hosts.', validation: { validate: { required: requiredIfAdvanced(validationContext), }, }, + after: ({ form, fields }) => ( + + ), }, maxRPCPriceMillion: { category: 'gouging', type: 'siacoin', title: 'Max RPC price', description: ( - <> - The max allowed base price for RPCs in siacoins per million calls. - Choose whether to set the price in siacoin per million calls or to pin - the siacoin price to a fixed fiat value per million calls. - + <>The max allowed base price for RPCs in siacoins per million calls. ), units: 'SC/million', decimalsLimitSc: scDecimalPlaces, + suggestion: new BigNumber(10), + suggestionTip: 'The suggested value is 10 SC.', + tipsDecimalsLimitSc: 0, hidden: configViewMode === 'basic', - average: averagesSc?.rpcAverage, - averageTip: 'Averages provided by Sia Central.', - suggestionTip: 'This value will help you match with more hosts.', validation: { validate: { required: requiredIfAdvanced(validationContext), diff --git a/apps/renterd/contexts/config/useAutopilotEvaluations.tsx b/apps/renterd/contexts/config/useAutopilotEvaluations.tsx index 272bdbd9a..9915950de 100644 --- a/apps/renterd/contexts/config/useAutopilotEvaluations.tsx +++ b/apps/renterd/contexts/config/useAutopilotEvaluations.tsx @@ -365,7 +365,7 @@ function getRecommendationItem({ const format = (val: BigNumber) => `${humanSiacoin(toHastings(val), { fixed: 1, - })}${fields[key].units?.replace('SC/', '/')}` + })}${fields[key].units?.replace('SC/', '/') || ''}` rec.currentLabel = format(currentValue) rec.targetLabel = format(targetValue) } diff --git a/apps/renterd/contexts/config/useAverages.tsx b/apps/renterd/contexts/config/useAverages.tsx index 24f9e298e..0ecfcf53c 100644 --- a/apps/renterd/contexts/config/useAverages.tsx +++ b/apps/renterd/contexts/config/useAverages.tsx @@ -7,12 +7,9 @@ import { valuePerOneToPerMillion, } from '@siafoundation/units' import { useSiaCentralHostsNetworkAverages } from '@siafoundation/sia-central-react' -import { UseFormReturn } from 'react-hook-form' -import { InputValues } from './types' -import { useFormExchangeRate } from './useFormExchangeRate' -export function useAverages({ form }: { form: UseFormReturn }) { - const averages = useSiaCentralHostsNetworkAverages({ +export function useAverages() { + const siaCentralAverages = useSiaCentralHostsNetworkAverages({ config: { swr: { revalidateOnFocus: false, @@ -21,60 +18,61 @@ export function useAverages({ form }: { form: UseFormReturn }) { }) const storageAverage = useMemo( () => - averages.data + siaCentralAverages.data ? new BigNumber( valuePerBytePerBlockToPerTBPerMonth( - toSiacoins(averages.data.settings.storage_price) + toSiacoins(siaCentralAverages.data.settings.storage_price) ).toFixed(0) ) : undefined, - [averages.data] + [siaCentralAverages.data] ) const uploadAverage = useMemo( () => - averages.data + siaCentralAverages.data ? new BigNumber( valuePerByteToPerTB( - toSiacoins(averages.data.settings.upload_price) + toSiacoins(siaCentralAverages.data.settings.upload_price) ).toFixed(0) ) : undefined, - [averages.data] + [siaCentralAverages.data] ) const downloadAverage = useMemo( () => - averages.data + siaCentralAverages.data ? new BigNumber( valuePerByteToPerTB( - toSiacoins(averages.data.settings.download_price) + toSiacoins(siaCentralAverages.data.settings.download_price) ).toFixed(0) ) : undefined, - [averages.data] + [siaCentralAverages.data] ) const contractAverage = useMemo( () => - averages.data + siaCentralAverages.data ? new BigNumber( - toSiacoins(averages.data.settings.contract_price).toFixed(0) + toSiacoins(siaCentralAverages.data.settings.contract_price).toFixed( + 0 + ) ) : undefined, - [averages.data] + [siaCentralAverages.data] ) const rpcAverage = useMemo( () => - averages.data + siaCentralAverages.data ? valuePerOneToPerMillion( - toSiacoins(averages.data.settings.base_rpc_price) + toSiacoins(siaCentralAverages.data.settings.base_rpc_price) ) : undefined, - [averages.data] + [siaCentralAverages.data] ) - const { rate } = useFormExchangeRate(form) - const averagesSc = useMemo(() => { + const averages = useMemo(() => { if ( !storageAverage || !uploadAverage || @@ -82,7 +80,7 @@ export function useAverages({ form }: { form: UseFormReturn }) { !contractAverage || !rpcAverage ) { - return undefined + return {} } return { storageAverage, @@ -99,35 +97,5 @@ export function useAverages({ form }: { form: UseFormReturn }) { rpcAverage, ]) - const averagesFiat = useMemo(() => { - if ( - !rate || - !storageAverage || - !uploadAverage || - !downloadAverage || - !contractAverage || - !rpcAverage - ) { - return undefined - } - return { - storageAverage: storageAverage.times(rate), - uploadAverage: uploadAverage.times(rate), - downloadAverage: downloadAverage.times(rate), - contractAverage: contractAverage.times(rate), - rpcAverage: rpcAverage.times(rate), - } - }, [ - rate, - storageAverage, - uploadAverage, - downloadAverage, - contractAverage, - rpcAverage, - ]) - - return { - averagesSc, - averagesFiat, - } + return averages } diff --git a/apps/renterd/contexts/config/useForm.tsx b/apps/renterd/contexts/config/useForm.tsx index aca33b8d8..3a94c8f7c 100644 --- a/apps/renterd/contexts/config/useForm.tsx +++ b/apps/renterd/contexts/config/useForm.tsx @@ -1,7 +1,6 @@ import { useEffect, useMemo, useRef } from 'react' import { ConfigViewMode, inputValues, getAdvancedDefaults } from './types' import { useForm as useHookForm } from 'react-hook-form' -import { useAverages } from './useAverages' import { useBusState } from '@siafoundation/renterd-react' import { getFields } from './fields' import { useApp } from '../app' @@ -28,8 +27,6 @@ export function useForm({ resources }: { resources: ResourcesMaybeLoaded }) { [minShards, totalShards] ) - const { averagesSc, averagesFiat } = useAverages({ form }) - const { isAutopilotEnabled } = useApp() const [configViewMode, setConfigViewMode] = useLocalStorageState('v0/config/mode', { @@ -72,17 +69,6 @@ export function useForm({ resources }: { resources: ResourcesMaybeLoaded }) { [rec.key]: rec, } }, {}) - if (averagesSc) { - return getFields({ - validationContext: validationContext.current, - isAutopilotEnabled, - configViewMode, - advancedDefaults, - averagesSc, - averagesFiat, - recommendations, - }) - } return getFields({ validationContext: validationContext.current, isAutopilotEnabled, @@ -94,8 +80,6 @@ export function useForm({ resources }: { resources: ResourcesMaybeLoaded }) { isAutopilotEnabled, configViewMode, renterdState.data, - averagesSc, - averagesFiat, evaluation.recommendations, ]) diff --git a/libs/design-system/src/app/CurrencyFiatSelector.tsx b/libs/design-system/src/app/CurrencyFiatSelector.tsx index af4ae5b69..8640b3a0a 100644 --- a/libs/design-system/src/app/CurrencyFiatSelector.tsx +++ b/libs/design-system/src/app/CurrencyFiatSelector.tsx @@ -8,6 +8,8 @@ export function CurrencyFiatSelector() { return (