diff --git a/.changeset/cold-keys-wash.md b/.changeset/cold-keys-wash.md
new file mode 100644
index 000000000..eba16a12e
--- /dev/null
+++ b/.changeset/cold-keys-wash.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/renterd-types': patch
+---
+
+Host and contract responses are now Nullable rather than Maybe, since empty responses return null.
diff --git a/.changeset/cuddly-balloons-raise.md b/.changeset/cuddly-balloons-raise.md
new file mode 100644
index 000000000..9c497de96
--- /dev/null
+++ b/.changeset/cuddly-balloons-raise.md
@@ -0,0 +1,7 @@
+---
+'hostd': patch
+'renterd': patch
+'walletd': patch
+---
+
+Fixed a bug where the transaction list would show pending transactions when viewing pages other than the first page.
diff --git a/.changeset/fluffy-snails-hope.md b/.changeset/fluffy-snails-hope.md
new file mode 100644
index 000000000..56d75597b
--- /dev/null
+++ b/.changeset/fluffy-snails-hope.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/react-core': minor
+---
+
+Added maybeFromNullishArrayResponse for casting null empty array responses to [].
diff --git a/.changeset/hip-years-sin.md b/.changeset/hip-years-sin.md
new file mode 100644
index 000000000..876c3fb4c
--- /dev/null
+++ b/.changeset/hip-years-sin.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/design-system': minor
+---
+
+Refactored useDatasetState to include a noneOnPage state, a renamed loaded state, and a more explicit API.
diff --git a/.changeset/nice-maps-dress.md b/.changeset/nice-maps-dress.md
new file mode 100644
index 000000000..1b5ae1e11
--- /dev/null
+++ b/.changeset/nice-maps-dress.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/design-system': minor
+---
+
+PaginationMarker now explicitly takes a nextMarker and does not disable down navigation.
diff --git a/.changeset/old-planes-happen.md b/.changeset/old-planes-happen.md
new file mode 100644
index 000000000..6edc0c2d8
--- /dev/null
+++ b/.changeset/old-planes-happen.md
@@ -0,0 +1,5 @@
+---
+'renterd': patch
+---
+
+Fixed a bug where pagination did now work on the file explorer all files mode.
diff --git a/.changeset/slow-tools-cheat.md b/.changeset/slow-tools-cheat.md
new file mode 100644
index 000000000..4b0f94c94
--- /dev/null
+++ b/.changeset/slow-tools-cheat.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/design-system': minor
+---
+
+Added EmptyState component for handling all dataset empty states with custom or default components.
diff --git a/.changeset/spotty-fans-shave.md b/.changeset/spotty-fans-shave.md
new file mode 100644
index 000000000..92f5eaf72
--- /dev/null
+++ b/.changeset/spotty-fans-shave.md
@@ -0,0 +1,7 @@
+---
+'hostd': minor
+'renterd': minor
+'walletd': minor
+---
+
+Data tables now show an empty state when viewing a page greater than the first page with no data.
diff --git a/apps/hostd-e2e/src/specs/contracts.spec.ts b/apps/hostd-e2e/src/specs/contracts.spec.ts
index 6e79fa3ef..ceeba02e0 100644
--- a/apps/hostd-e2e/src/specs/contracts.spec.ts
+++ b/apps/hostd-e2e/src/specs/contracts.spec.ts
@@ -1,7 +1,12 @@
import { test, expect } from '@playwright/test'
import { navigateToContracts } from '../fixtures/navigate'
import { afterTest, beforeTest } from '../fixtures/beforeTest'
-import { getContractRows, getContractRowsAll } from '../fixtures/contracts'
+import {
+ getContractRowById,
+ getContractRowByIndex,
+ getContractRows,
+ getContractRowsAll,
+} from '../fixtures/contracts'
test.beforeEach(async ({ page }) => {
await beforeTest(page, {
@@ -35,3 +40,17 @@ test('new contracts do not show a renewed from or to contract', async ({
await expect(getContractRows(page).getByTestId('renewedFrom')).toBeHidden()
await expect(getContractRows(page).getByTestId('renewedTo')).toBeHidden()
})
+
+test('viewing a page with no data shows the correct empty state', async ({
+ page,
+}) => {
+ await page.goto('/contracts?offset=100')
+ // Check that the empty state is correct.
+ await expect(
+ page.getByText('No data on this page, reset pagination to continue.')
+ ).toBeVisible()
+ await expect(page.getByText('Back to first page')).toBeVisible()
+ await page.getByText('Back to first page').click()
+ // Ensure we are now seeing rows of data.
+ await getContractRowByIndex(page, 0, true)
+})
diff --git a/apps/renterd/components/Wallet/WalletFilterBar.tsx b/apps/renterd/components/Wallet/WalletFilterBar.tsx
index 1c8eb1746..d3a72fa43 100644
--- a/apps/renterd/components/Wallet/WalletFilterBar.tsx
+++ b/apps/renterd/components/Wallet/WalletFilterBar.tsx
@@ -9,7 +9,6 @@ export function WalletFilterBar() {
const { isSynced, syncPercent, isWalletSynced, walletScanPercent } =
useSyncStatus()
const { offset, limit, pageCount, datasetState } = useTransactions()
- console.log(pageCount)
return (
}
pageSize={6}
- data={dataset}
+ data={datasetPage}
context={cellContext}
columns={columns}
sortableColumns={sortableColumns}
diff --git a/apps/walletd/components/WalletsList/WalletsFiltersBar.tsx b/apps/walletd/components/WalletsList/WalletsFiltersBar.tsx
index cbfcb6a12..121ca2944 100644
--- a/apps/walletd/components/WalletsList/WalletsFiltersBar.tsx
+++ b/apps/walletd/components/WalletsList/WalletsFiltersBar.tsx
@@ -4,7 +4,7 @@ import { useWallets } from '../../contexts/wallets'
import { pluralize } from '@siafoundation/units'
export function WalletsFiltersBar() {
- const { pageCount: datasetCount, unlockedCount } = useWallets()
+ const { datasetCount, unlockedCount } = useWallets()
return (
diff --git a/apps/walletd/contexts/events/index.tsx b/apps/walletd/contexts/events/index.tsx
index 942a62ac5..ccfef164a 100644
--- a/apps/walletd/contexts/events/index.tsx
+++ b/apps/walletd/contexts/events/index.tsx
@@ -172,7 +172,7 @@ export function useEventsMain() {
error: responseEvents.error,
pageCount: datasetPage?.length || 0,
columns: filteredTableColumns,
- dataset: datasetPage,
+ datasetPage,
cellContext,
configurableColumns,
enabledColumns,
diff --git a/apps/walletd/contexts/wallets/index.tsx b/apps/walletd/contexts/wallets/index.tsx
index 79ccff749..e3a7a0f95 100644
--- a/apps/walletd/contexts/wallets/index.tsx
+++ b/apps/walletd/contexts/wallets/index.tsx
@@ -52,7 +52,7 @@ function useWalletsMain() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
- const dataset = useMemo>(() => {
+ const _dataset = useMemo>(() => {
if (!response.data) {
return undefined
}
@@ -102,7 +102,7 @@ function useWalletsMain() {
cacheWalletMnemonic,
])
- const wallet = dataset?.find((w) => w.id === (router.query.id as string))
+ const wallet = _dataset?.find((w) => w.id === (router.query.id as string))
const { filters, setFilter, removeFilter, removeLastFilter, resetFilters } =
useClientFilters()
@@ -127,8 +127,8 @@ function useWalletsMain() {
defaultSortField,
})
- const datasetPage = useClientFilteredDataset({
- dataset,
+ const dataset = useClientFilteredDataset({
+ dataset: _dataset,
filters,
sortField,
sortDirection,
@@ -143,7 +143,7 @@ function useWalletsMain() {
)
const datasetState = useDatasetState({
- datasetPage,
+ datasetPage: dataset,
isValidating: response.isValidating,
error: response.error,
filters,
@@ -160,10 +160,10 @@ function useWalletsMain() {
return {
datasetState,
error: response.error,
- pageCount: datasetPage?.length || 0,
+ datasetCount: dataset?.length || 0,
unlockedCount: cachedMnemonicCount,
columns: filteredTableColumns,
- datasetPage,
+ dataset,
context,
wallet,
configurableColumns,
diff --git a/libs/design-system/src/components/EmptyState/StateError.tsx b/libs/design-system/src/components/EmptyState/StateError.tsx
index 7f35eb623..25adda91e 100644
--- a/libs/design-system/src/components/EmptyState/StateError.tsx
+++ b/libs/design-system/src/components/EmptyState/StateError.tsx
@@ -1,4 +1,4 @@
-import { Text } from '@siafoundation/design-system'
+import { Text } from '../../core/Text'
import { MisuseOutline32 } from '@siafoundation/react-icons'
import { SWRError } from '@siafoundation/react-core'
diff --git a/libs/design-system/src/components/EmptyState/StateNoData.tsx b/libs/design-system/src/components/EmptyState/StateNoData.tsx
index 80c6aa8b2..95475811f 100644
--- a/libs/design-system/src/components/EmptyState/StateNoData.tsx
+++ b/libs/design-system/src/components/EmptyState/StateNoData.tsx
@@ -1,4 +1,4 @@
-import { Text } from '@siafoundation/design-system'
+import { Text } from '../../core/Text'
import { ChartArea32 } from '@siafoundation/react-icons'
export function StateNoData() {
diff --git a/libs/design-system/src/components/EmptyState/StateNoneMatching.tsx b/libs/design-system/src/components/EmptyState/StateNoneMatching.tsx
index 28451c2d2..ddbd19f49 100644
--- a/libs/design-system/src/components/EmptyState/StateNoneMatching.tsx
+++ b/libs/design-system/src/components/EmptyState/StateNoneMatching.tsx
@@ -1,4 +1,4 @@
-import { Text } from '@siafoundation/design-system'
+import { Text } from '../../core/Text'
import { Filter32 } from '@siafoundation/react-icons'
export function StateNoneMatching() {
diff --git a/libs/design-system/src/components/EmptyState/StateNoneOnPage.tsx b/libs/design-system/src/components/EmptyState/StateNoneOnPage.tsx
index bccd71c2e..a6c7a9b9d 100644
--- a/libs/design-system/src/components/EmptyState/StateNoneOnPage.tsx
+++ b/libs/design-system/src/components/EmptyState/StateNoneOnPage.tsx
@@ -1,4 +1,5 @@
-import { Button, Text } from '@siafoundation/design-system'
+import { Button } from '../../core/Button'
+import { Text } from '../../core/Text'
import { usePagesRouter } from '@siafoundation/next'
import { Reset32 } from '@siafoundation/react-icons'
import { useCallback } from 'react'
diff --git a/libs/design-system/src/components/EmptyState/StateNoneYet.tsx b/libs/design-system/src/components/EmptyState/StateNoneYet.tsx
index 14a9970fa..ca6a75b6d 100644
--- a/libs/design-system/src/components/EmptyState/StateNoneYet.tsx
+++ b/libs/design-system/src/components/EmptyState/StateNoneYet.tsx
@@ -1,4 +1,4 @@
-import { Text } from '@siafoundation/design-system'
+import { Text } from '../../core/Text'
import { DataBase32 } from '@siafoundation/react-icons'
export function StateNoneYet() {
diff --git a/libs/design-system/src/components/EmptyState/index.tsx b/libs/design-system/src/components/EmptyState/index.tsx
index ce203989e..e643187a5 100644
--- a/libs/design-system/src/components/EmptyState/index.tsx
+++ b/libs/design-system/src/components/EmptyState/index.tsx
@@ -1,9 +1,9 @@
-import { DatasetState } from '@siafoundation/design-system'
import { StateNoneMatching } from './StateNoneMatching'
import { StateNoneYet } from './StateNoneYet'
import { StateError } from './StateError'
import { StateNoneOnPage } from './StateNoneOnPage'
import React from 'react'
+import { DatasetState } from '../../hooks/useDatasetState'
export function EmptyState({
datasetState,
diff --git a/libs/design-system/src/components/PaginatorMarker.tsx b/libs/design-system/src/components/PaginatorMarker.tsx
index f6995331e..9ef406415 100644
--- a/libs/design-system/src/components/PaginatorMarker.tsx
+++ b/libs/design-system/src/components/PaginatorMarker.tsx
@@ -60,17 +60,14 @@ export function PaginatorMarker({
size="small"
variant="gray"
className="rounded-none"
- onClick={() => {
- console.log('xxx', {
- marker: nextMarker,
- })
+ onClick={() =>
router.push({
query: {
...router.query,
marker: nextMarker,
},
})
- }}
+ }
>