From 2540a0e16a0b6e34fd18d0c9f43eeff84fdea2b5 Mon Sep 17 00:00:00 2001 From: Alex Freska Date: Mon, 16 Dec 2024 10:29:39 -0500 Subject: [PATCH] feat(renterd): bulk rescan hosts --- .changeset/itchy-shoes-lick.md | 5 ++ apps/renterd-e2e/src/specs/contracts.spec.ts | 12 ++++ apps/renterd-e2e/src/specs/hosts.spec.ts | 12 ++++ .../ContractsRescanHosts.tsx | 15 +++++ .../Contracts/ContractsBulkMenu/index.tsx | 2 + .../Hosts/HostsBulkMenu/HostsRescan.tsx | 15 +++++ .../components/Hosts/HostsBulkMenu/index.tsx | 2 + .../bulkActions/BulkRescanHosts.tsx | 56 +++++++++++++++++++ 8 files changed, 119 insertions(+) create mode 100644 .changeset/itchy-shoes-lick.md create mode 100644 apps/renterd/components/Contracts/ContractsBulkMenu/ContractsRescanHosts.tsx create mode 100644 apps/renterd/components/Hosts/HostsBulkMenu/HostsRescan.tsx create mode 100644 apps/renterd/components/bulkActions/BulkRescanHosts.tsx diff --git a/.changeset/itchy-shoes-lick.md b/.changeset/itchy-shoes-lick.md new file mode 100644 index 000000000..210b30f9a --- /dev/null +++ b/.changeset/itchy-shoes-lick.md @@ -0,0 +1,5 @@ +--- +'renterd': minor +--- + +The host and contracts multi-select menus both now include an option to rescan the selected hosts. diff --git a/apps/renterd-e2e/src/specs/contracts.spec.ts b/apps/renterd-e2e/src/specs/contracts.spec.ts index 6cd8eeb9d..03e03fb7f 100644 --- a/apps/renterd-e2e/src/specs/contracts.spec.ts +++ b/apps/renterd-e2e/src/specs/contracts.spec.ts @@ -79,6 +79,18 @@ test('contracts bulk delete', async ({ page }) => { await expect(page.getByText('3 contracts deleted')).toBeVisible() }) +test('contracts bulk rescan', async ({ page }) => { + await navigateToContracts({ page }) + const rows = await getContractRowsAll(page) + rows.at(0).click() + rows.at(-1).click({ modifiers: ['Shift'] }) + + // Rescan selected hosts. + const menu = page.getByLabel('contract multi-select menu') + await menu.getByLabel('rescan selected hosts').click() + await expect(page.getByText('rescanning 3 hosts')).toBeVisible() +}) + test('contracts bulk allowlist', async ({ page }) => { await navigateToContracts({ page }) const rows = await getContractRowsAll(page) diff --git a/apps/renterd-e2e/src/specs/hosts.spec.ts b/apps/renterd-e2e/src/specs/hosts.spec.ts index 641a40d21..91b7d5ede 100644 --- a/apps/renterd-e2e/src/specs/hosts.spec.ts +++ b/apps/renterd-e2e/src/specs/hosts.spec.ts @@ -77,6 +77,18 @@ test('hosts bulk allowlist', async ({ page }) => { ).toHaveCount(3) }) +test('hosts bulk rescan', async ({ page }) => { + await navigateToHosts({ page }) + const rows = await getHostRowsAll(page) + rows.at(0).click() + rows.at(-1).click({ modifiers: ['Shift'], position: { x: 5, y: 5 } }) + + // Rescan selected hosts. + const menu = page.getByLabel('host multi-select menu') + await menu.getByLabel('rescan selected hosts').click() + await expect(page.getByText('rescanning 3 hosts')).toBeVisible() +}) + test('hosts bulk blocklist', async ({ page }) => { await navigateToHosts({ page }) const rows = await getHostRowsAll(page) diff --git a/apps/renterd/components/Contracts/ContractsBulkMenu/ContractsRescanHosts.tsx b/apps/renterd/components/Contracts/ContractsBulkMenu/ContractsRescanHosts.tsx new file mode 100644 index 000000000..930359bd4 --- /dev/null +++ b/apps/renterd/components/Contracts/ContractsBulkMenu/ContractsRescanHosts.tsx @@ -0,0 +1,15 @@ +import { useMemo } from 'react' +import { useContracts } from '../../../contexts/contracts' +import { BulkRescanHosts } from '../../bulkActions/BulkRescanHosts' + +export function ContractsRescanHosts() { + const { multiSelect } = useContracts() + + const publicKeys = useMemo( + () => + Object.entries(multiSelect.selection).map(([_, item]) => item.hostKey), + [multiSelect.selection] + ) + + return +} diff --git a/apps/renterd/components/Contracts/ContractsBulkMenu/index.tsx b/apps/renterd/components/Contracts/ContractsBulkMenu/index.tsx index 3d26a754c..b9c1e7e11 100644 --- a/apps/renterd/components/Contracts/ContractsBulkMenu/index.tsx +++ b/apps/renterd/components/Contracts/ContractsBulkMenu/index.tsx @@ -5,6 +5,7 @@ import { ContractsAddBlocklist } from './ContractsAddBlocklist' import { ContractsAddAllowlist } from './ContractsAddAllowlist' import { ContractsRemoveBlocklist } from './ContractsRemoveBlocklist' import { ContractsRemoveAllowlist } from './ContractsRemoveAllowlist' +import { ContractsRescanHosts } from './ContractsRescanHosts' export function ContractsBulkMenu() { const { multiSelect } = useContracts() @@ -19,6 +20,7 @@ export function ContractsBulkMenu() { + ) diff --git a/apps/renterd/components/Hosts/HostsBulkMenu/HostsRescan.tsx b/apps/renterd/components/Hosts/HostsBulkMenu/HostsRescan.tsx new file mode 100644 index 000000000..e366f7a8b --- /dev/null +++ b/apps/renterd/components/Hosts/HostsBulkMenu/HostsRescan.tsx @@ -0,0 +1,15 @@ +import { useMemo } from 'react' +import { BulkRescanHosts } from '../../bulkActions/BulkRescanHosts' +import { useHosts } from '../../../contexts/hosts' + +export function HostsRescan() { + const { multiSelect } = useHosts() + + const publicKeys = useMemo( + () => + Object.entries(multiSelect.selection).map(([_, item]) => item.publicKey), + [multiSelect.selection] + ) + + return +} diff --git a/apps/renterd/components/Hosts/HostsBulkMenu/index.tsx b/apps/renterd/components/Hosts/HostsBulkMenu/index.tsx index c020341a6..5c5f5751d 100644 --- a/apps/renterd/components/Hosts/HostsBulkMenu/index.tsx +++ b/apps/renterd/components/Hosts/HostsBulkMenu/index.tsx @@ -5,6 +5,7 @@ import { HostsAddAllowlist } from './HostsAddAllowlist' import { HostsRemoveBlocklist } from './HostsRemoveBlocklist' import { HostsRemoveAllowlist } from './HostsRemoveAllowlist' import { useHosts } from '../../../contexts/hosts' +import { HostsRescan } from './HostsRescan' export function HostsBulkMenu() { const { multiSelect } = useHosts() @@ -19,6 +20,7 @@ export function HostsBulkMenu() { + ) diff --git a/apps/renterd/components/bulkActions/BulkRescanHosts.tsx b/apps/renterd/components/bulkActions/BulkRescanHosts.tsx new file mode 100644 index 000000000..5bcf01d34 --- /dev/null +++ b/apps/renterd/components/bulkActions/BulkRescanHosts.tsx @@ -0,0 +1,56 @@ +import { + Button, + handleBatchOperation, + MultiSelect, + MultiSelectRow, +} from '@siafoundation/design-system' +import { DataView16 } from '@siafoundation/react-icons' +import { useHostScan } from '@siafoundation/renterd-react' +import { useCallback } from 'react' +import { pluralize, secondsInMilliseconds } from '@siafoundation/units' + +export function BulkRescanHosts({ + multiSelect, + publicKeys, +}: { + multiSelect: MultiSelect + publicKeys: string[] +}) { + const scan = useHostScan() + const scanAll = useCallback(async () => { + await handleBatchOperation( + publicKeys.map((publicKey) => + scan.post({ + params: { + hostkey: publicKey, + }, + payload: { + timeout: secondsInMilliseconds(30), + }, + }) + ), + { + toastError: ({ successCount, errorCount, totalCount }) => ({ + title: `Rescanning ${pluralize(successCount, 'host')}`, + body: `Error starting rescan for ${errorCount}/${totalCount} of total hosts.`, + }), + toastSuccess: ({ totalCount }) => ({ + title: `Rescanning ${pluralize(totalCount, 'host')}`, + }), + after: () => { + multiSelect.deselectAll() + }, + } + ) + }, [multiSelect, publicKeys, scan]) + + return ( + + ) +}