Skip to content

Commit 33ec74b

Browse files
authored
feat: add pv list page (#287)
Signed-off-by: Zzde <zhangxh1997@gmail.com>
1 parent b9f3d84 commit 33ec74b

File tree

4 files changed

+161
-0
lines changed

4 files changed

+161
-0
lines changed

ui/src/i18n/locales/en.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,13 @@
459459
"capacity": "Capacity",
460460
"accessModes": "Access Modes"
461461
},
462+
"pvs": {
463+
"storageClass": "Storage Class",
464+
"capacity": "Capacity",
465+
"accessModes": "Access Modes",
466+
"reclaimPolicy": "Reclaim Policy",
467+
"claim": "Claim"
468+
},
462469
"detail": {
463470
"buttons": {
464471
"refresh": "Refresh",

ui/src/i18n/locales/zh.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,5 +590,18 @@
590590
"hints": {
591591
"nameImmutable": "创建后名称不可更改"
592592
}
593+
},
594+
"pvcs": {
595+
"volume": "",
596+
"storageClass": "存储类",
597+
"capacity": "容量",
598+
"accessModes": "访问模式"
599+
},
600+
"pvs": {
601+
"storageClass": "存储类",
602+
"capacity": "容量",
603+
"accessModes": "访问模式",
604+
"reclaimPolicy": "回收策略",
605+
"claim": "声明"
593606
}
594607
}

ui/src/pages/pv-list-page.tsx

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { useCallback, useMemo } from 'react'
2+
import { createColumnHelper } from '@tanstack/react-table'
3+
import { PersistentVolume } from 'kubernetes-types/core/v1'
4+
import { useTranslation } from 'react-i18next'
5+
import { Link } from 'react-router-dom'
6+
7+
import { formatDate, parseBytes } from '@/lib/utils'
8+
import { Badge } from '@/components/ui/badge'
9+
import { ResourceTable } from '@/components/resource-table'
10+
11+
export function PVListPage() {
12+
const { t } = useTranslation()
13+
const columnHelper = createColumnHelper<PersistentVolume>()
14+
15+
// Define columns for the PV table
16+
const columns = useMemo(
17+
() => [
18+
columnHelper.accessor('metadata.name', {
19+
header: t('common.name'),
20+
cell: ({ row }) => (
21+
<div className="font-medium text-blue-500 hover:underline">
22+
<Link to={`/persistentvolumes/${row.original.metadata!.name}`}>
23+
{row.original.metadata!.name}
24+
</Link>
25+
</div>
26+
),
27+
}),
28+
columnHelper.accessor('status.phase', {
29+
header: t('common.status'),
30+
enableColumnFilter: true,
31+
cell: ({ getValue }) => {
32+
const phase = getValue() || 'Unknown'
33+
let variant: 'default' | 'destructive' | 'secondary' = 'secondary'
34+
35+
switch (phase) {
36+
case 'Bound':
37+
variant = 'default'
38+
break
39+
case 'Available':
40+
variant = 'secondary'
41+
break
42+
case 'Released':
43+
case 'Failed':
44+
variant = 'destructive'
45+
break
46+
}
47+
48+
return <Badge variant={variant}>{phase}</Badge>
49+
},
50+
}),
51+
columnHelper.accessor('spec.storageClassName', {
52+
header: t('pvs.storageClass'),
53+
enableColumnFilter: true,
54+
cell: ({ getValue }) => {
55+
const scName = getValue()
56+
if (scName) {
57+
return (
58+
<div className="font-medium text-blue-500 hover:underline">
59+
<Link to={`/storageclasses/${scName}`}>{scName}</Link>
60+
</div>
61+
)
62+
}
63+
return '-'
64+
},
65+
}),
66+
columnHelper.accessor(
67+
(row) => parseBytes(row.spec?.capacity?.storage || '0'),
68+
{
69+
header: t('pvs.capacity'),
70+
cell: ({ row }) => row.original.spec?.capacity?.storage || '-',
71+
}
72+
),
73+
columnHelper.accessor('spec.accessModes', {
74+
header: t('pvs.accessModes'),
75+
cell: ({ getValue }) => {
76+
const modes = getValue() || []
77+
return modes.join(', ') || '-'
78+
},
79+
}),
80+
columnHelper.accessor('spec.persistentVolumeReclaimPolicy', {
81+
header: t('pvs.reclaimPolicy'),
82+
cell: ({ getValue }) => {
83+
const policy = getValue()
84+
return policy || '-'
85+
},
86+
}),
87+
columnHelper.accessor('spec.claimRef', {
88+
header: t('pvs.claim'),
89+
cell: ({ getValue }) => {
90+
const claimRef = getValue()
91+
if (claimRef && claimRef.name && claimRef.namespace) {
92+
return (
93+
<div className="font-medium text-blue-500 hover:underline">
94+
<Link
95+
to={`/persistentvolumeclaims/${claimRef.namespace}/${claimRef.name}`}
96+
>
97+
{claimRef.namespace}/{claimRef.name}
98+
</Link>
99+
</div>
100+
)
101+
}
102+
return '-'
103+
},
104+
}),
105+
columnHelper.accessor('metadata.creationTimestamp', {
106+
header: t('common.created'),
107+
cell: ({ getValue }) => {
108+
const dateStr = formatDate(getValue() || '')
109+
110+
return (
111+
<span className="text-muted-foreground text-sm">{dateStr}</span>
112+
)
113+
},
114+
}),
115+
],
116+
[columnHelper, t]
117+
)
118+
119+
// Custom filter for PV search
120+
const pvSearchFilter = useCallback((pv: PersistentVolume, query: string) => {
121+
return (
122+
pv.metadata!.name!.toLowerCase().includes(query) ||
123+
(pv.spec!.storageClassName?.toLowerCase() || '').includes(query) ||
124+
(pv.status!.phase?.toLowerCase() || '').includes(query) ||
125+
(pv.spec!.claimRef?.name?.toLowerCase() || '').includes(query) ||
126+
(pv.spec!.claimRef?.namespace?.toLowerCase() || '').includes(query)
127+
)
128+
}, [])
129+
130+
return (
131+
<ResourceTable
132+
resourceName={'PersistentVolumes'}
133+
columns={columns}
134+
clusterScope={true}
135+
searchQueryFilter={pvSearchFilter}
136+
/>
137+
)
138+
}

ui/src/pages/resource-list.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { JobListPage } from './job-list-page'
1717
import { NamespaceListPage } from './namespace-list-page'
1818
import { NodeListPage } from './node-list-page'
1919
import { PodListPage } from './pod-list-page'
20+
import { PVListPage } from './pv-list-page'
2021
import { PVCListPage } from './pvc-list-page'
2122
import { SecretListPage } from './secret-list-page'
2223
import { ServiceListPage } from './service-list-page'
@@ -59,6 +60,8 @@ export function ResourceList() {
5960
return <SecretListPage />
6061
case 'persistentvolumeclaims':
6162
return <PVCListPage />
63+
case 'persistentvolumes':
64+
return <PVListPage />
6265
case 'crds':
6366
return <CRDListPage />
6467
case 'gateways':

0 commit comments

Comments
 (0)