diff --git a/.changeset/few-bees-compete.md b/.changeset/few-bees-compete.md new file mode 100644 index 000000000..fc2d1ea95 --- /dev/null +++ b/.changeset/few-bees-compete.md @@ -0,0 +1,5 @@ +--- +'hostd': patch +--- + +Refined the volume deletion toast message to "Volume is now being permanently deleted". Closes https://github.com/SiaFoundation/hostd/issues/409 diff --git a/apps/hostd-e2e/src/fixtures/navigate.ts b/apps/hostd-e2e/src/fixtures/navigate.ts new file mode 100644 index 000000000..bc8e4de0c --- /dev/null +++ b/apps/hostd-e2e/src/fixtures/navigate.ts @@ -0,0 +1,18 @@ +import { Page, expect } from '@playwright/test' + +export async function navigateToDashboard({ page }: { page: Page }) { + await page.getByLabel('Overview').click() + await expect(page.getByTestId('navbar').getByText('Overview')).toBeVisible() +} + +export async function navigateToConfig({ page }: { page: Page }) { + await page.getByLabel('Configuration').click() + await expect( + page.getByTestId('navbar').getByText('Configuration') + ).toBeVisible() +} + +export async function navigateToVolumes({ page }: { page: Page }) { + await page.getByLabel('Volumes').click() + await expect(page.getByTestId('navbar').getByText('Volumes')).toBeVisible() +} diff --git a/apps/hostd-e2e/src/fixtures/navigateToDashboard.ts b/apps/hostd-e2e/src/fixtures/navigateToDashboard.ts deleted file mode 100644 index 604eccf5d..000000000 --- a/apps/hostd-e2e/src/fixtures/navigateToDashboard.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Page, expect } from '@playwright/test' - -export async function navigateToDashboard({ page }: { page: Page }) { - await page.getByLabel('Overview').click() - await expect(page.getByTestId('navbar').getByText('Overview')).toBeVisible() -} diff --git a/apps/hostd-e2e/src/fixtures/volumes.ts b/apps/hostd-e2e/src/fixtures/volumes.ts new file mode 100644 index 000000000..ad506022c --- /dev/null +++ b/apps/hostd-e2e/src/fixtures/volumes.ts @@ -0,0 +1,63 @@ +import { Page, expect } from '@playwright/test' +import { navigateToVolumes } from './navigate' +import { fillTextInputByName } from './textInput' +import { clearToasts } from './clearToasts' + +export async function createVolume(page: Page, name: string, path: string) { + await navigateToVolumes({ page }) + await page.getByText('Create volume').click() + await fillTextInputByName(page, 'name', name) + await fillTextInputByName(page, 'immediatePath', path) + // immediatePath updates path after 500ms + // eslint-disable-next-line playwright/no-wait-for-timeout + await page.waitForTimeout(1000) + await fillTextInputByName(page, 'size', '11') + await expect( + page.getByRole('dialog').getByText('Must be between 10.00 GB') + ).toBeHidden() + await page.locator('input[name=size]').press('Enter') + await expect(page.getByRole('dialog')).toBeHidden() + const row = page.getByRole('row', { name }) + await expect(row.getByText('creating')).toBeVisible() + await expect(page.getByText('Volume created')).toBeVisible() + await clearToasts({ page }) + await expect(page.getByRole('cell', { name })).toBeVisible() +} + +export async function deleteVolume(page: Page, name: string, path: string) { + await openVolumeContextMenu(page, path) + await page.getByRole('menuitem', { name: 'Delete' }).click() + await fillTextInputByName(page, 'path', `${path}/${name}`) + await page.locator('input[name=path]').press('Enter') + await expect(page.getByRole('dialog')).toBeHidden() + await expect( + page.getByText('Volume is now being permanently deleted') + ).toBeVisible() + await volumeNotInList(page, name) +} + +export async function deleteVolumeIfExists( + page: Page, + name: string, + path: string +) { + const doesVolumeExist = await page + .getByRole('table') + .getByText(name) + .isVisible() + if (doesVolumeExist) { + await deleteVolume(page, name, path) + } +} + +export async function openVolumeContextMenu(page: Page, name: string) { + await page.getByRole('row', { name }).getByRole('button').first().click() +} + +export async function volumeInList(page: Page, name: string) { + await expect(page.getByRole('table').getByText(name)).toBeVisible() +} + +export async function volumeNotInList(page: Page, name: string) { + await expect(page.getByRole('table').getByText(name)).toBeHidden() +} diff --git a/apps/hostd-e2e/src/specs/config.spec.ts b/apps/hostd-e2e/src/specs/config.spec.ts index 40524a93f..2239c0b5f 100644 --- a/apps/hostd-e2e/src/specs/config.spec.ts +++ b/apps/hostd-e2e/src/specs/config.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test' import { login } from '../fixtures/login' import { expectSwitchByLabel, setSwitchByLabel } from '../fixtures/switchValue' import { setViewMode } from '../fixtures/configViewMode' -import { navigateToConfig } from '../fixtures/navigateToConfig' +import { navigateToConfig } from '../fixtures/navigate' import { mockApiSiaCentralExchangeRates } from '@siafoundation/sia-central-mock' import { configResetAllSettings } from '../fixtures/configResetAllSettings' import { diff --git a/apps/hostd-e2e/src/specs/volumes.spec.ts b/apps/hostd-e2e/src/specs/volumes.spec.ts new file mode 100644 index 000000000..a9f95a37b --- /dev/null +++ b/apps/hostd-e2e/src/specs/volumes.spec.ts @@ -0,0 +1,18 @@ +import { test } from '@playwright/test' +import { navigateToVolumes } from '../fixtures/navigate' +import { login } from '../fixtures/login' +import { + createVolume, + deleteVolume, + deleteVolumeIfExists, +} from '../fixtures/volumes' + +test('can create and delete a volume', async ({ page }) => { + const name = 'my-new-bucket' + const path = '/tmp' + await login({ page }) + await navigateToVolumes({ page }) + await deleteVolumeIfExists(page, name, path) + await createVolume(page, name, path) + await deleteVolume(page, name, path) +}) diff --git a/apps/hostd/dialogs/VolumeCreateDialog.tsx b/apps/hostd/dialogs/VolumeCreateDialog.tsx index 660d01abc..17121cee2 100644 --- a/apps/hostd/dialogs/VolumeCreateDialog.tsx +++ b/apps/hostd/dialogs/VolumeCreateDialog.tsx @@ -37,10 +37,12 @@ const defaultValues = { immediatePath: '~', } +type Values = typeof defaultValues + function getFields( minSizeGB: number, maxSizeGB: number -): ConfigFields { +): ConfigFields { return { name: { type: 'text', @@ -128,7 +130,7 @@ export function VolumeCreateDialog({ trigger, open, onOpenChange }: Props) { }, [path]) const onSubmit = useCallback( - async (values) => { + async (values: Values) => { const response = await volumeAdd.post({ payload: { localPath: joinPaths(path, name, separator), @@ -202,7 +204,9 @@ export function VolumeCreateDialog({ trigger, open, onOpenChange }: Props) { const onInvalid = useOnInvalid(fields) - form.register('path', fields.path.validation) + useEffect(() => { + form.register('path', fields.path.validation) + }, [form, fields.path.validation]) return ( { +type Values = typeof defaultValues + +function getFields(path: string): ConfigFields { return { path: { type: 'text', @@ -71,7 +73,7 @@ export function VolumeDeleteDialog({ trigger, open, onOpenChange }: Props) { }) const onSubmit = useCallback( - async (values: typeof defaultValues) => { + async (values: Values) => { const response = await volumeDelete.delete({ params: { id: volume.data?.id, @@ -84,7 +86,9 @@ export function VolumeDeleteDialog({ trigger, open, onOpenChange }: Props) { body: response.error, }) } else { - triggerSuccessToast({ title: 'Volume permanently deleted' }) + triggerSuccessToast({ + title: 'Volume is now being permanently deleted', + }) form.reset() closeDialog() } diff --git a/apps/renterd-e2e/src/fixtures/buckets.ts b/apps/renterd-e2e/src/fixtures/buckets.ts index 36dea103e..cb57944e7 100644 --- a/apps/renterd-e2e/src/fixtures/buckets.ts +++ b/apps/renterd-e2e/src/fixtures/buckets.ts @@ -1,11 +1,10 @@ import { Page, expect } from '@playwright/test' -import { navigateToBuckets } from './navigateToBuckets' +import { navigateToBuckets } from './navigate' import { fillTextInputByName } from './textInput' import { clearToasts } from './clearToasts' export async function createBucket(page: Page, name: string) { await navigateToBuckets({ page }) - await expect(page.getByTestId('navbar').getByText('Buckets')).toBeVisible() await page.getByText('Create bucket').click() await fillTextInputByName(page, 'name', name) await page.locator('input[name=name]').press('Enter') diff --git a/apps/hostd-e2e/src/fixtures/navigateToConfig.ts b/apps/renterd-e2e/src/fixtures/navigate.ts similarity index 57% rename from apps/hostd-e2e/src/fixtures/navigateToConfig.ts rename to apps/renterd-e2e/src/fixtures/navigate.ts index 5cfb6114d..6493dcf19 100644 --- a/apps/hostd-e2e/src/fixtures/navigateToConfig.ts +++ b/apps/renterd-e2e/src/fixtures/navigate.ts @@ -1,5 +1,10 @@ import { Page, expect } from '@playwright/test' +export async function navigateToBuckets({ page }: { page: Page }) { + await page.getByLabel('Files').click() + await expect(page.getByTestId('navbar').getByText('Buckets')).toBeVisible() +} + export async function navigateToConfig({ page }: { page: Page }) { await page.getByLabel('Configuration').click() await expect( diff --git a/apps/renterd-e2e/src/fixtures/navigateToBuckets.ts b/apps/renterd-e2e/src/fixtures/navigateToBuckets.ts deleted file mode 100644 index 7c6ef4b16..000000000 --- a/apps/renterd-e2e/src/fixtures/navigateToBuckets.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Page, expect } from '@playwright/test' - -export async function navigateToBuckets({ page }: { page: Page }) { - await page.getByLabel('Files').click() - await expect(page.getByTestId('navbar').getByText('Buckets')).toBeVisible() -} diff --git a/apps/renterd-e2e/src/fixtures/navigateToConfig.ts b/apps/renterd-e2e/src/fixtures/navigateToConfig.ts deleted file mode 100644 index 5cfb6114d..000000000 --- a/apps/renterd-e2e/src/fixtures/navigateToConfig.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Page, expect } from '@playwright/test' - -export async function navigateToConfig({ page }: { page: Page }) { - await page.getByLabel('Configuration').click() - await expect( - page.getByTestId('navbar').getByText('Configuration') - ).toBeVisible() -} diff --git a/apps/renterd-e2e/src/specs/buckets.spec.ts b/apps/renterd-e2e/src/specs/buckets.spec.ts index 5376bb7dd..afb5019f5 100644 --- a/apps/renterd-e2e/src/specs/buckets.spec.ts +++ b/apps/renterd-e2e/src/specs/buckets.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from '@playwright/test' -import { navigateToBuckets } from '../fixtures/navigateToBuckets' +import { navigateToBuckets } from '../fixtures/navigate' import { login } from '../fixtures/login' import { bucketInList, diff --git a/apps/renterd-e2e/src/specs/config.spec.ts b/apps/renterd-e2e/src/specs/config.spec.ts index aebdc4095..211e85e50 100644 --- a/apps/renterd-e2e/src/specs/config.spec.ts +++ b/apps/renterd-e2e/src/specs/config.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test' import { login } from '../fixtures/login' import { expectSwitchByLabel, setSwitchByLabel } from '../fixtures/switchValue' import { setViewMode } from '../fixtures/configViewMode' -import { navigateToConfig } from '../fixtures/navigateToConfig' +import { navigateToConfig } from '../fixtures/navigate' import { mockApiSiaCentralExchangeRates } from '@siafoundation/sia-central-mock' import { expectTextInputByName,