From 615a7aaff39aa59e86c03b3e2ee86094958eca91 Mon Sep 17 00:00:00 2001 From: silent-cipher Date: Thu, 15 Jan 2026 11:55:41 +0530 Subject: [PATCH 1/4] feat: add check activity column to provider tables --- .../data/column-definition.tsx | 19 +++++++++---------- .../data/column-definition.tsx | 19 +++++++++---------- src/schemas/provider-schema.ts | 2 +- src/services/providers/index.ts | 16 +++++++++++----- src/utils/provider-urls.ts | 18 ++++++++++++++++++ 5 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 src/utils/provider-urls.ts diff --git a/src/app/service-providers/data/column-definition.tsx b/src/app/service-providers/data/column-definition.tsx index 921e6fcd..809d2e55 100644 --- a/src/app/service-providers/data/column-definition.tsx +++ b/src/app/service-providers/data/column-definition.tsx @@ -1,6 +1,6 @@ import { ID } from '@filecoin-foundation/ui-filecoin/Table/ID' import { YesNoStatus } from '@filecoin-foundation/ui-filecoin/Table/YesNoStatus' -// import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink' +import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink' import { createColumnHelper } from '@tanstack/react-table' import { CompactPeerID } from '@/components/CompactPeerID' @@ -52,15 +52,14 @@ export const columns = [ sortingFn: sortSoftwareVersion, sortUndefined: 'last', }), - // TODO: Add check activity link - // columnHelper.accessor('checkActivityUrl', { - // header: 'Check Activity', - // cell: (info) => ( - // - // View on PDP Scan - // - // ), - // }), + columnHelper.accessor('checkActivityUrl', { + header: 'Check Activity', + cell: (info) => ( + + View on PDP Scan + + ), + }), // TODO: Add Service Offered Column columnHelper.accessor('serviceStatus', { header: 'Status', diff --git a/src/app/warm-storage-service/data/column-definition.tsx b/src/app/warm-storage-service/data/column-definition.tsx index 5bb0a2be..809f67c8 100644 --- a/src/app/warm-storage-service/data/column-definition.tsx +++ b/src/app/warm-storage-service/data/column-definition.tsx @@ -1,5 +1,5 @@ import { ID } from '@filecoin-foundation/ui-filecoin/Table/ID' -// import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink' +import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink' import { createColumnHelper } from '@tanstack/react-table' import { CompactPeerID } from '@/components/CompactPeerID' @@ -45,15 +45,14 @@ export const columns = [ sortingFn: sortSoftwareVersion, sortUndefined: 'last', }), - // TODO: Add check activity link - // columnHelper.accessor('checkActivityUrl', { - // header: 'Check Activity', - // cell: (info) => ( - // - // View on PDP Scan - // - // ), - // }), + columnHelper.accessor('checkActivityUrl', { + header: 'Check Activity', + cell: (info) => ( + + View on PDP Scan + + ), + }), columnHelper.accessor('location', { header: 'Location', cell: (info) => info.getValue(), diff --git a/src/schemas/provider-schema.ts b/src/schemas/provider-schema.ts index 151e07d1..25b3e075 100644 --- a/src/schemas/provider-schema.ts +++ b/src/schemas/provider-schema.ts @@ -9,7 +9,7 @@ const ethereumAddressSchema = z.custom
( export const providerSchema = z.object({ capabilityKeys: z.array(z.string()), capacityTb: z.bigint().optional(), - // checkActivityUrl: z.url().optional(), // TODO: Remove optional + checkActivityUrl: z.url(), description: z.string(), id: z.number(), ipniIpfs: z.boolean(), diff --git a/src/services/providers/index.ts b/src/services/providers/index.ts index 2cfcc9b8..0c2833dc 100644 --- a/src/services/providers/index.ts +++ b/src/services/providers/index.ts @@ -12,6 +12,7 @@ import { type ServiceProvider, } from '@/schemas/provider-schema' import type { FetchProvidersOptions, ProviderFilter } from '@/types/providers' +import { getCheckActivityUrl } from '@/utils/provider-urls' import { VERSION_FETCH_CONCURRENCY } from './constants' import { @@ -79,10 +80,11 @@ async function fetchProvidersByFilter( } /** - * Enrich providers with software version information + * Enrich providers with additional information (software version and check activity URL) */ -async function enrichProvidersWithVersions( +async function enrichProviders( providers: ProviderWithoutSoftwareVersion[], + network: Network, ): Promise { const providersWithVersions: Array< ProviderWithoutSoftwareVersion & { softwareVersion?: string } @@ -94,7 +96,11 @@ async function enrichProvidersWithVersions( const batchResults = await Promise.all( batch.map(async (provider) => { const softwareVersion = await fetchSoftwareVersion(provider.serviceUrl) - return { ...provider, softwareVersion } + const checkActivityUrl = getCheckActivityUrl( + network, + provider.payeeAddress, + ) + return { ...provider, softwareVersion, checkActivityUrl } }), ) providersWithVersions.push(...batchResults) @@ -178,6 +184,6 @@ export async function fetchProviders( serviceRegistry, }) - // Enrich with software versions - return enrichProvidersWithVersions(fetchedProviders) + // Enrich with additional information + return enrichProviders(fetchedProviders, network) } diff --git a/src/utils/provider-urls.ts b/src/utils/provider-urls.ts new file mode 100644 index 00000000..1851d110 --- /dev/null +++ b/src/utils/provider-urls.ts @@ -0,0 +1,18 @@ +import type { Address } from 'viem' + +import type { Network } from '@/config/chains' +import { EXPLORERS } from '@/constants/external-services' + +/** + * Constructs the check activity URL for a provider on PDP Scan + * + * @param network - The network (mainnet or calibration) + * @param payeeAddress - The provider's payee address + * @returns The full URL to view provider activity on PDP Scan + */ +export function getCheckActivityUrl( + network: Network, + payeeAddress: Address, +): string { + return `${EXPLORERS.PDP_SCAN[network]}${payeeAddress}` +} From 7f8b3c41f71f6be21d4c6f628f767661cbba42b5 Mon Sep 17 00:00:00 2001 From: silent-cipher Date: Thu, 15 Jan 2026 12:11:17 +0530 Subject: [PATCH 2/4] refactor: rename to BaseProviderData and update type definition --- src/services/providers/contract.ts | 8 ++++---- src/services/providers/index.ts | 11 +++++------ src/services/providers/processor.ts | 4 ++-- src/services/providers/types.ts | 6 +++--- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/services/providers/contract.ts b/src/services/providers/contract.ts index 6686e824..21c34374 100644 --- a/src/services/providers/contract.ts +++ b/src/services/providers/contract.ts @@ -4,7 +4,7 @@ import type { ServiceRegistryABI, WarmStorageViewABI } from '@/config/abis' import { BATCH_SIZE, PDP_PRODUCT_TYPE, PROVIDER_FETCH_LIMIT } from './constants' import { processProviderData } from './processor' -import type { ProviderWithoutSoftwareVersion } from './types' +import type { BaseProviderData } from './types' /** * Fetch approved provider IDs from WarmStorageView contract with pagination @@ -50,8 +50,8 @@ export async function fetchProvidersBulk( >, onlyActive: boolean, approvedProviderIds?: Set, -): Promise { - const providers: ProviderWithoutSoftwareVersion[] = [] +): Promise { + const providers: BaseProviderData[] = [] let offset = 0 let hasMore = true @@ -117,7 +117,7 @@ export async function fetchProviderById( PublicClient >, isApproved = false, -): Promise { +): Promise { const providerData = await serviceRegistryContract.read.getProviderWithProduct([ providerId, diff --git a/src/services/providers/index.ts b/src/services/providers/index.ts index 0c2833dc..b7f15c7d 100644 --- a/src/services/providers/index.ts +++ b/src/services/providers/index.ts @@ -20,7 +20,7 @@ import { fetchProviderById, fetchProvidersBulk, } from './contract' -import type { ProviderWithoutSoftwareVersion } from './types' +import type { BaseProviderData } from './types' import { fetchSoftwareVersion } from './version' /** @@ -35,7 +35,7 @@ async function fetchProvidersByFilter( PublicClient > }, -): Promise { +): Promise { const { storageView, serviceRegistry } = contracts // Fetch approved provider IDs for marking providers @@ -71,8 +71,7 @@ async function fetchProvidersByFilter( const providers = await Promise.all(providerPromises) return providers.filter( - (provider): provider is ProviderWithoutSoftwareVersion => - provider !== null, + (provider): provider is BaseProviderData => provider !== null, ) } @@ -83,11 +82,11 @@ async function fetchProvidersByFilter( * Enrich providers with additional information (software version and check activity URL) */ async function enrichProviders( - providers: ProviderWithoutSoftwareVersion[], + providers: BaseProviderData[], network: Network, ): Promise { const providersWithVersions: Array< - ProviderWithoutSoftwareVersion & { softwareVersion?: string } + BaseProviderData & { softwareVersion?: string; checkActivityUrl?: string } > = [] // Process providers in batches diff --git a/src/services/providers/processor.ts b/src/services/providers/processor.ts index 83968523..ea6d1cb6 100644 --- a/src/services/providers/processor.ts +++ b/src/services/providers/processor.ts @@ -5,7 +5,7 @@ import type { ProviderData } from '@/types/contract-types' import { decodePDPCapabilities } from '@/utils/decode-pdp-capabilities' import { parseLocation } from '@/utils/parse-location' -import type { ProviderWithoutSoftwareVersion } from './types' +import type { BaseProviderData } from './types' const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' @@ -40,7 +40,7 @@ function buildCapabilities( export function processProviderData( providerData: ProviderData, isApproved = false, -): ProviderWithoutSoftwareVersion | undefined { +): BaseProviderData | undefined { const { providerId, providerInfo, product, productCapabilityValues } = providerData diff --git a/src/services/providers/types.ts b/src/services/providers/types.ts index ddbe67ed..45f8c700 100644 --- a/src/services/providers/types.ts +++ b/src/services/providers/types.ts @@ -1,9 +1,9 @@ import type { ServiceProvider } from '@/schemas/provider-schema' /** - * Provider without software version (before version fetch) + * Base provider data from contract (before enrichment with software version and check activity URL) */ -export type ProviderWithoutSoftwareVersion = Omit< +export type BaseProviderData = Omit< ServiceProvider, - 'softwareVersion' + 'softwareVersion' | 'checkActivityUrl' > From 9e11e01e56391357512e063fcc205a6b90d69525 Mon Sep 17 00:00:00 2001 From: silent-cipher Date: Thu, 15 Jan 2026 13:08:38 +0530 Subject: [PATCH 3/4] feat: disable sorting for check activity column --- src/app/service-providers/data/column-definition.tsx | 1 + src/app/warm-storage-service/data/column-definition.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/app/service-providers/data/column-definition.tsx b/src/app/service-providers/data/column-definition.tsx index 809d2e55..a20ad33c 100644 --- a/src/app/service-providers/data/column-definition.tsx +++ b/src/app/service-providers/data/column-definition.tsx @@ -59,6 +59,7 @@ export const columns = [ View on PDP Scan ), + enableSorting: false, }), // TODO: Add Service Offered Column columnHelper.accessor('serviceStatus', { diff --git a/src/app/warm-storage-service/data/column-definition.tsx b/src/app/warm-storage-service/data/column-definition.tsx index 809f67c8..12e4e5a1 100644 --- a/src/app/warm-storage-service/data/column-definition.tsx +++ b/src/app/warm-storage-service/data/column-definition.tsx @@ -52,6 +52,7 @@ export const columns = [ View on PDP Scan ), + enableSorting: false, }), columnHelper.accessor('location', { header: 'Location', From d270a71a50d7cc40e4eca9bb95df6e3d92dcec89 Mon Sep 17 00:00:00 2001 From: silent-cipher Date: Tue, 27 Jan 2026 13:06:00 +0530 Subject: [PATCH 4/4] chore: address review --- .../data/column-definition.tsx | 9 +++++---- .../data/column-definition.tsx | 9 +++++---- src/components/PdpScanLink.tsx | 17 +++++++++++++++++ src/services/providers/index.ts | 4 +--- 4 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 src/components/PdpScanLink.tsx diff --git a/src/app/service-providers/data/column-definition.tsx b/src/app/service-providers/data/column-definition.tsx index a20ad33c..185e2c5e 100644 --- a/src/app/service-providers/data/column-definition.tsx +++ b/src/app/service-providers/data/column-definition.tsx @@ -1,9 +1,9 @@ import { ID } from '@filecoin-foundation/ui-filecoin/Table/ID' import { YesNoStatus } from '@filecoin-foundation/ui-filecoin/Table/YesNoStatus' -import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink' import { createColumnHelper } from '@tanstack/react-table' import { CompactPeerID } from '@/components/CompactPeerID' +import { PdpScanLink } from '@/components/PdpScanLink' import { ProviderOverview } from '@/components/ProviderOverview' import { SoftwareVersion } from '@/components/SoftwareVersion' @@ -55,9 +55,10 @@ export const columns = [ columnHelper.accessor('checkActivityUrl', { header: 'Check Activity', cell: (info) => ( - - View on PDP Scan - + ), enableSorting: false, }), diff --git a/src/app/warm-storage-service/data/column-definition.tsx b/src/app/warm-storage-service/data/column-definition.tsx index 12e4e5a1..073deec8 100644 --- a/src/app/warm-storage-service/data/column-definition.tsx +++ b/src/app/warm-storage-service/data/column-definition.tsx @@ -1,8 +1,8 @@ import { ID } from '@filecoin-foundation/ui-filecoin/Table/ID' -import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink' import { createColumnHelper } from '@tanstack/react-table' import { CompactPeerID } from '@/components/CompactPeerID' +import { PdpScanLink } from '@/components/PdpScanLink' import { ProviderOverview } from '@/components/ProviderOverview' import { SoftwareVersion } from '@/components/SoftwareVersion' @@ -48,9 +48,10 @@ export const columns = [ columnHelper.accessor('checkActivityUrl', { header: 'Check Activity', cell: (info) => ( - - View on PDP Scan - + ), enableSorting: false, }), diff --git a/src/components/PdpScanLink.tsx b/src/components/PdpScanLink.tsx new file mode 100644 index 00000000..f1fb3332 --- /dev/null +++ b/src/components/PdpScanLink.tsx @@ -0,0 +1,17 @@ +import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink' + +type PdpScanLinkProps = { + pdpScanUrl: string + providerName: string +} + +export function PdpScanLink({ pdpScanUrl, providerName }: PdpScanLinkProps) { + return ( + + View on PDP Scan + + ) +} diff --git a/src/services/providers/index.ts b/src/services/providers/index.ts index b7f15c7d..44bded9a 100644 --- a/src/services/providers/index.ts +++ b/src/services/providers/index.ts @@ -85,9 +85,7 @@ async function enrichProviders( providers: BaseProviderData[], network: Network, ): Promise { - const providersWithVersions: Array< - BaseProviderData & { softwareVersion?: string; checkActivityUrl?: string } - > = [] + const providersWithVersions: ServiceProvider[] = [] // Process providers in batches for (let i = 0; i < providers.length; i += VERSION_FETCH_CONCURRENCY) {