Skip to content

Commit 75e65cd

Browse files
authored
feat: support view crd yaml (#229)
1 parent 3c7d940 commit 75e65cd

File tree

2 files changed

+64
-13
lines changed

2 files changed

+64
-13
lines changed

ui/src/components/resource-table.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useEffect, useMemo, useState } from 'react'
1+
import React, { useCallback, useEffect, useMemo, useState } from 'react'
22
import {
33
ColumnDef,
44
ColumnFiltersState,
@@ -71,6 +71,7 @@ export interface ResourceTableProps<T> {
7171
searchQueryFilter?: (item: T, query: string) => boolean // Custom filter function
7272
showCreateButton?: boolean // If true, show create button
7373
onCreateClick?: () => void // Callback for create button click
74+
extraToolbars?: React.ReactNode[] // Additional toolbar components
7475
}
7576

7677
export function ResourceTable<T>({
@@ -81,6 +82,7 @@ export function ResourceTable<T>({
8182
searchQueryFilter,
8283
showCreateButton = false,
8384
onCreateClick,
85+
extraToolbars = [],
8486
}: ResourceTableProps<T>) {
8587
const { t } = useTranslation()
8688
const [sorting, setSorting] = useState<SortingState>([])
@@ -116,7 +118,6 @@ export function ResourceTable<T>({
116118
: storedNamespace || 'default' // Default to 'default' if not set
117119
})
118120
const [useSSE, setUseSSE] = useState(false)
119-
120121
const {
121122
isLoading: queryLoading,
122123
data: queryData,
@@ -367,7 +368,6 @@ export function ResourceTable<T>({
367368
setIsDeleting(false)
368369
}
369370
}, [table, clusterScope, resourceType, resourceName, t, useSSE, refetch])
370-
371371
// Calculate total and filtered row counts
372372
const totalRowCount = useMemo(
373373
() => (data as T[] | undefined)?.length || 0,
@@ -503,6 +503,9 @@ export function ResourceTable<T>({
503503

504504
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
505505
<div className="flex items-center gap-2 flex-wrap">
506+
{extraToolbars?.map((toolbar, index) => (
507+
<React.Fragment key={index}>{toolbar}</React.Fragment>
508+
))}
506509
{/* Watch/Live mode toggle switch */}
507510
{resourceName === 'Pods' && (
508511
<div className="flex items-center gap-2">

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

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,49 @@
1-
import { useCallback, useMemo } from 'react'
1+
import { useCallback, useMemo, useState } from 'react'
22
import { createColumnHelper } from '@tanstack/react-table'
3+
import * as yaml from 'js-yaml'
4+
import { CustomResourceDefinition } from 'kubernetes-types/apiextensions/v1'
35
import { get } from 'lodash'
6+
import { Eye } from 'lucide-react'
47
import { Link, useParams } from 'react-router-dom'
58

69
import { CustomResource, ResourceType } from '@/types/api'
710
import { useResource } from '@/lib/api'
811
import { formatDate } from '@/lib/utils'
12+
import { Button } from '@/components/ui/button'
13+
import {
14+
Dialog,
15+
DialogContent,
16+
DialogHeader,
17+
DialogTitle,
18+
} from '@/components/ui/dialog'
919
import { ResourceTable } from '@/components/resource-table'
20+
import { YamlEditor } from '@/components/yaml-editor'
1021

1122
export function CRListPage() {
23+
const [isYamlDialogOpen, setIsYamlDialogOpen] = useState(false)
24+
const [yamlContent, setYamlContent] = useState('')
1225
const { crd } = useParams<{ crd: string }>()
1326
const { data: crdData, isLoading: isLoadingCRD } = useResource('crds', crd!)
1427

1528
const columnHelper = createColumnHelper<CustomResource>()
16-
29+
const handleViewYaml = useCallback((crd: CustomResourceDefinition) => {
30+
setYamlContent(yaml.dump(crd, { indent: 2 }))
31+
setIsYamlDialogOpen(true)
32+
}, [])
33+
const extraToolbars = useMemo(() => {
34+
return [
35+
<Button
36+
variant="outline"
37+
size="default"
38+
onClick={() => {
39+
handleViewYaml(crdData as CustomResourceDefinition)
40+
}}
41+
>
42+
<Eye className="h-4 w-4 mr-1" />
43+
View YAML
44+
</Button>,
45+
]
46+
}, [crdData, handleViewYaml])
1747
const columns = useMemo(() => {
1848
const baseColumns = [
1949
columnHelper.accessor('metadata.name', {
@@ -33,7 +63,6 @@ export function CRListPage() {
3363
},
3464
}),
3565
]
36-
3766
const additionalColumns =
3867
crdData?.spec.versions[0].additionalPrinterColumns?.map(
3968
(printerColumn) => {
@@ -91,12 +120,31 @@ export function CRListPage() {
91120
}
92121

93122
return (
94-
<ResourceTable
95-
resourceName={crdData.spec.names.kind || 'Custom Resources'}
96-
resourceType={crd as ResourceType}
97-
columns={columns}
98-
clusterScope={crdData.spec.scope === 'Cluster'}
99-
searchQueryFilter={searchQueryFilter}
100-
/>
123+
<>
124+
<ResourceTable
125+
resourceName={crdData.spec.names.kind || 'Custom Resources'}
126+
resourceType={crd as ResourceType}
127+
columns={columns}
128+
clusterScope={crdData.spec.scope === 'Cluster'}
129+
searchQueryFilter={searchQueryFilter}
130+
extraToolbars={extraToolbars}
131+
/>
132+
133+
<Dialog open={isYamlDialogOpen} onOpenChange={setIsYamlDialogOpen}>
134+
<DialogContent className="sm:max-w-4xl max-h-[90vh] overflow-y-auto">
135+
<DialogHeader>
136+
<DialogTitle>
137+
YAML Configuration: {crdData?.metadata?.name ?? 'Unknown'}
138+
</DialogTitle>
139+
</DialogHeader>
140+
<YamlEditor
141+
value={yamlContent}
142+
readOnly={true}
143+
showControls={false}
144+
minHeight={600}
145+
/>
146+
</DialogContent>
147+
</Dialog>
148+
</>
101149
)
102150
}

0 commit comments

Comments
 (0)