Skip to content

Commit a697afe

Browse files
authored
Merge pull request #213 from FilOzone/feat/check-activity-url
feat: add check activity column to provider tables
2 parents 3428945 + d270a71 commit a697afe

File tree

9 files changed

+83
-43
lines changed

9 files changed

+83
-43
lines changed

src/app/service-providers/data/column-definition.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { ID } from '@filecoin-foundation/ui-filecoin/Table/ID'
22
import { YesNoStatus } from '@filecoin-foundation/ui-filecoin/Table/YesNoStatus'
3-
// import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink'
43
import { createColumnHelper } from '@tanstack/react-table'
54

65
import { CompactPeerID } from '@/components/CompactPeerID'
6+
import { PdpScanLink } from '@/components/PdpScanLink'
77
import { ProviderOverview } from '@/components/ProviderOverview'
88
import { SoftwareVersion } from '@/components/SoftwareVersion'
99

@@ -52,15 +52,16 @@ export const columns = [
5252
sortingFn: sortSoftwareVersion,
5353
sortUndefined: 'last',
5454
}),
55-
// TODO: Add check activity link
56-
// columnHelper.accessor('checkActivityUrl', {
57-
// header: 'Check Activity',
58-
// cell: (info) => (
59-
// <ExternalTextLink href={info.getValue() || '#todo'}>
60-
// View on PDP Scan
61-
// </ExternalTextLink>
62-
// ),
63-
// }),
55+
columnHelper.accessor('checkActivityUrl', {
56+
header: 'Check Activity',
57+
cell: (info) => (
58+
<PdpScanLink
59+
pdpScanUrl={info.getValue()}
60+
providerName={info.row.original.name}
61+
/>
62+
),
63+
enableSorting: false,
64+
}),
6465
// TODO: Add Service Offered Column
6566
columnHelper.accessor('serviceStatus', {
6667
header: 'Status',

src/app/warm-storage-service/data/column-definition.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { ID } from '@filecoin-foundation/ui-filecoin/Table/ID'
2-
// import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink'
32
import { createColumnHelper } from '@tanstack/react-table'
43

54
import { CompactPeerID } from '@/components/CompactPeerID'
5+
import { PdpScanLink } from '@/components/PdpScanLink'
66
import { ProviderOverview } from '@/components/ProviderOverview'
77
import { SoftwareVersion } from '@/components/SoftwareVersion'
88

@@ -45,15 +45,16 @@ export const columns = [
4545
sortingFn: sortSoftwareVersion,
4646
sortUndefined: 'last',
4747
}),
48-
// TODO: Add check activity link
49-
// columnHelper.accessor('checkActivityUrl', {
50-
// header: 'Check Activity',
51-
// cell: (info) => (
52-
// <ExternalTextLink href={info.getValue() || '#todo'}>
53-
// View on PDP Scan
54-
// </ExternalTextLink>
55-
// ),
56-
// }),
48+
columnHelper.accessor('checkActivityUrl', {
49+
header: 'Check Activity',
50+
cell: (info) => (
51+
<PdpScanLink
52+
pdpScanUrl={info.getValue()}
53+
providerName={info.row.original.name}
54+
/>
55+
),
56+
enableSorting: false,
57+
}),
5758
columnHelper.accessor('location', {
5859
header: 'Location',
5960
cell: (info) => info.getValue(),

src/components/PdpScanLink.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ExternalTextLink } from '@filecoin-foundation/ui-filecoin/TextLink/ExternalTextLink'
2+
3+
type PdpScanLinkProps = {
4+
pdpScanUrl: string
5+
providerName: string
6+
}
7+
8+
export function PdpScanLink({ pdpScanUrl, providerName }: PdpScanLinkProps) {
9+
return (
10+
<ExternalTextLink
11+
href={pdpScanUrl}
12+
aria-label={`View activity for provider ${providerName} on PDP Scan`}
13+
>
14+
View on PDP Scan
15+
</ExternalTextLink>
16+
)
17+
}

src/schemas/provider-schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const ethereumAddressSchema = z.custom<Address>(
99
export const providerSchema = z.object({
1010
capabilityKeys: z.array(z.string()),
1111
capacityTb: z.bigint().optional(),
12-
// checkActivityUrl: z.url().optional(), // TODO: Remove optional
12+
checkActivityUrl: z.url(),
1313
description: z.string(),
1414
id: z.number(),
1515
ipniIpfs: z.boolean(),

src/services/providers/contract.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { ServiceRegistryABI, WarmStorageViewABI } from '@/config/abis'
44

55
import { BATCH_SIZE, PDP_PRODUCT_TYPE, PROVIDER_FETCH_LIMIT } from './constants'
66
import { processProviderData } from './processor'
7-
import type { ProviderWithoutSoftwareVersion } from './types'
7+
import type { BaseProviderData } from './types'
88

99
/**
1010
* Fetch approved provider IDs from WarmStorageView contract with pagination
@@ -50,8 +50,8 @@ export async function fetchProvidersBulk(
5050
>,
5151
onlyActive: boolean,
5252
approvedProviderIds?: Set<bigint>,
53-
): Promise<ProviderWithoutSoftwareVersion[]> {
54-
const providers: ProviderWithoutSoftwareVersion[] = []
53+
): Promise<BaseProviderData[]> {
54+
const providers: BaseProviderData[] = []
5555
let offset = 0
5656
let hasMore = true
5757

@@ -117,7 +117,7 @@ export async function fetchProviderById(
117117
PublicClient
118118
>,
119119
isApproved = false,
120-
): Promise<ProviderWithoutSoftwareVersion | undefined> {
120+
): Promise<BaseProviderData | undefined> {
121121
const providerData =
122122
await serviceRegistryContract.read.getProviderWithProduct([
123123
providerId,

src/services/providers/index.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ import {
1212
type ServiceProvider,
1313
} from '@/schemas/provider-schema'
1414
import type { FetchProvidersOptions, ProviderFilter } from '@/types/providers'
15+
import { getCheckActivityUrl } from '@/utils/provider-urls'
1516

1617
import { VERSION_FETCH_CONCURRENCY } from './constants'
1718
import {
1819
fetchApprovedProviderIds,
1920
fetchProviderById,
2021
fetchProvidersBulk,
2122
} from './contract'
22-
import type { ProviderWithoutSoftwareVersion } from './types'
23+
import type { BaseProviderData } from './types'
2324
import { fetchSoftwareVersion } from './version'
2425

2526
/**
@@ -34,7 +35,7 @@ async function fetchProvidersByFilter(
3435
PublicClient
3536
>
3637
},
37-
): Promise<ProviderWithoutSoftwareVersion[]> {
38+
): Promise<BaseProviderData[]> {
3839
const { storageView, serviceRegistry } = contracts
3940

4041
// Fetch approved provider IDs for marking providers
@@ -70,31 +71,33 @@ async function fetchProvidersByFilter(
7071

7172
const providers = await Promise.all(providerPromises)
7273
return providers.filter(
73-
(provider): provider is ProviderWithoutSoftwareVersion =>
74-
provider !== null,
74+
(provider): provider is BaseProviderData => provider !== null,
7575
)
7676
}
7777

7878
throw new Error(`Invalid filter type: ${filter}`)
7979
}
8080

8181
/**
82-
* Enrich providers with software version information
82+
* Enrich providers with additional information (software version and check activity URL)
8383
*/
84-
async function enrichProvidersWithVersions(
85-
providers: ProviderWithoutSoftwareVersion[],
84+
async function enrichProviders(
85+
providers: BaseProviderData[],
86+
network: Network,
8687
): Promise<ServiceProvider[]> {
87-
const providersWithVersions: Array<
88-
ProviderWithoutSoftwareVersion & { softwareVersion?: string }
89-
> = []
88+
const providersWithVersions: ServiceProvider[] = []
9089

9190
// Process providers in batches
9291
for (let i = 0; i < providers.length; i += VERSION_FETCH_CONCURRENCY) {
9392
const batch = providers.slice(i, i + VERSION_FETCH_CONCURRENCY)
9493
const batchResults = await Promise.all(
9594
batch.map(async (provider) => {
9695
const softwareVersion = await fetchSoftwareVersion(provider.serviceUrl)
97-
return { ...provider, softwareVersion }
96+
const checkActivityUrl = getCheckActivityUrl(
97+
network,
98+
provider.payeeAddress,
99+
)
100+
return { ...provider, softwareVersion, checkActivityUrl }
98101
}),
99102
)
100103
providersWithVersions.push(...batchResults)
@@ -178,6 +181,6 @@ export async function fetchProviders(
178181
serviceRegistry,
179182
})
180183

181-
// Enrich with software versions
182-
return enrichProvidersWithVersions(fetchedProviders)
184+
// Enrich with additional information
185+
return enrichProviders(fetchedProviders, network)
183186
}

src/services/providers/processor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { ProviderData } from '@/types/contract-types'
55
import { decodePDPCapabilities } from '@/utils/decode-pdp-capabilities'
66
import { parseLocation } from '@/utils/parse-location'
77

8-
import type { ProviderWithoutSoftwareVersion } from './types'
8+
import type { BaseProviderData } from './types'
99

1010
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
1111

@@ -40,7 +40,7 @@ function buildCapabilities(
4040
export function processProviderData(
4141
providerData: ProviderData,
4242
isApproved = false,
43-
): ProviderWithoutSoftwareVersion | undefined {
43+
): BaseProviderData | undefined {
4444
const { providerId, providerInfo, product, productCapabilityValues } =
4545
providerData
4646

src/services/providers/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { ServiceProvider } from '@/schemas/provider-schema'
22

33
/**
4-
* Provider without software version (before version fetch)
4+
* Base provider data from contract (before enrichment with software version and check activity URL)
55
*/
6-
export type ProviderWithoutSoftwareVersion = Omit<
6+
export type BaseProviderData = Omit<
77
ServiceProvider,
8-
'softwareVersion'
8+
'softwareVersion' | 'checkActivityUrl'
99
>

src/utils/provider-urls.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { Address } from 'viem'
2+
3+
import type { Network } from '@/config/chains'
4+
import { EXPLORERS } from '@/constants/external-services'
5+
6+
/**
7+
* Constructs the check activity URL for a provider on PDP Scan
8+
*
9+
* @param network - The network (mainnet or calibration)
10+
* @param payeeAddress - The provider's payee address
11+
* @returns The full URL to view provider activity on PDP Scan
12+
*/
13+
export function getCheckActivityUrl(
14+
network: Network,
15+
payeeAddress: Address,
16+
): string {
17+
return `${EXPLORERS.PDP_SCAN[network]}${payeeAddress}`
18+
}

0 commit comments

Comments
 (0)