diff --git a/PROJECT_EVALUATION.md b/PROJECT_EVALUATION.md index f0ceaa1..060ce62 100644 --- a/PROJECT_EVALUATION.md +++ b/PROJECT_EVALUATION.md @@ -32,6 +32,7 @@ | Service/Ingress 列表 | ✅ | ✅ | ✅ | | HPA 列表/创建/删除 | ✅ | ✅ | ✅ | | ConfigMap/Secret 列表 | ✅ | ✅ | ✅ | +| ConfigMap/Secret 编辑 | ✅ UpdateResourceYAMLNS | ✅ YamlViewer(autoEdit) | ✅ curl 验证 | | Events 列表 | ✅ ListEvents | ✅ EventsPage | ✅ | | 容量分析 | ✅ GetCapacityAnalysis | ✅ CapacityPage | ✅ | | kubectl 终端 | ✅ KubectlShell(WS) | ✅ KubectlTerminal | ✅ | diff --git a/ROADMAP.md b/ROADMAP.md index 58c8a4a..a987766 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -54,16 +54,19 @@ --- -### M4: ConfigMap/Secret 编辑 [pending] +### M4: ConfigMap/Secret 编辑 [done] **目标**: 目前只读,增加在线编辑能力 **改动**: -- 复用已有 `UpdateResourceYAMLNS` 端点 -- 前端 ConfigMap/Secret 列表增加编辑弹窗(YAML 编辑器) +- 后端 `UpdateResourceYAMLNS` 端点已支持 configmaps/secrets(无需改动) +- 前端 `YamlViewer` 增加 `autoEdit` prop — 打开即进入编辑模式 +- `NamespaceResourcePage` ConfigMap/Secret 行增加显式编辑按钮(铅笔图标) +- 统一 `cleanBeforeEdit=true` — 编辑前自动清理 status/managedFields/uid 等只读字段 +- `k8s-yaml-utils.ts` 的 `cleanYAML()` 提供行级清理 **验收标准**: -- [ ] 可在线编辑 ConfigMap 并保存 -- [ ] 保存后 K8s 中实际生效 +- [x] 可在线编辑 ConfigMap 并保存 +- [x] 保存后 K8s 中实际生效(curl 验证 label 增删 → GET 确认) --- diff --git a/frontend/src/components/kubernetes/NamespaceResourcePage.tsx b/frontend/src/components/kubernetes/NamespaceResourcePage.tsx index 88ca425..b9a1696 100644 --- a/frontend/src/components/kubernetes/NamespaceResourcePage.tsx +++ b/frontend/src/components/kubernetes/NamespaceResourcePage.tsx @@ -13,7 +13,7 @@ import { import { RefreshCw, Search, Loader2, Boxes, Container, Network, FileText, Shield, Activity, Clock, ChevronRight, - Download, FileCode, + Download, FileCode, Pencil, } from 'lucide-react'; import { YamlViewer } from './YamlViewer'; import { kubernetesApi } from '@/services/api'; @@ -29,7 +29,7 @@ const RESOURCE_CONFIG: Record; columns: string[]; - renderRow: (item: any, opts: { clusterCode: string; namespace: string; onDetail?: (item: any) => void; onYaml?: (name: string) => void }) => React.ReactNode; + renderRow: (item: any, opts: { clusterCode: string; namespace: string; onDetail?: (item: any) => void; onYaml?: (name: string) => void; onEdit?: (name: string) => void }) => React.ReactNode; }> = { deployments: { title: 'Deployments', subtitle: 'Deployment 工作负载运行状态', icon: Boxes, @@ -120,7 +120,14 @@ const RESOURCE_CONFIG: Record{c.name} {c.namespace} {c.key_count || '-'} - + +
+ + +
+
), }, @@ -132,7 +139,14 @@ const RESOURCE_CONFIG: Record{s.name} {s.namespace} {s.type || '-'} - + +
+ + +
+
), }, @@ -227,7 +241,7 @@ export default function NamespaceResourcePage() { const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [search, setSearch] = useState(''); - const [yamlItem, setYamlItem] = useState<{resource: string; name: string} | null>(null); + const [yamlItem, setYamlItem] = useState<{resource: string; name: string; editMode?: boolean} | null>(null); useEffect(() => { kubernetesApi.getClusters().then((res: any) => { @@ -285,6 +299,7 @@ export default function NamespaceResourcePage() { }; const handleYaml = (name: string) => setYamlItem({ resource: type, name }); + const handleEdit = (name: string) => setYamlItem({ resource: type, name, editMode: true }); const handleExportCSV = () => kubernetesApi.exportAsCSV(`${type}-${clusterCode}-${namespace}.csv`, filtered); const handleExportJSON = () => kubernetesApi.exportAsJSON(`${type}-${clusterCode}-${namespace}.json`, filtered); @@ -314,6 +329,8 @@ export default function NamespaceResourcePage() { name={yamlItem.name} onClose={() => setYamlItem(null)} onSaved={loadData} + cleanBeforeEdit={true} + autoEdit={yamlItem.editMode === true} /> )}
@@ -369,7 +386,7 @@ export default function NamespaceResourcePage() { ) : filtered.length === 0 ? ( 暂无 {config.title} ) : ( - filtered.map((item) => config.renderRow(item, { clusterCode: clusterCode || '', namespace: namespace || '', onDetail: handleDetail, onYaml: handleYaml })) + filtered.map((item) => config.renderRow(item, { clusterCode: clusterCode || '', namespace: namespace || '', onDetail: handleDetail, onYaml: handleYaml, onEdit: handleEdit })) )} diff --git a/frontend/src/components/kubernetes/YamlViewer.tsx b/frontend/src/components/kubernetes/YamlViewer.tsx index b8cc405..caae69c 100644 --- a/frontend/src/components/kubernetes/YamlViewer.tsx +++ b/frontend/src/components/kubernetes/YamlViewer.tsx @@ -93,12 +93,12 @@ export function YamlViewer({ clusterCode, namespace, resource, name, onClose, on {!editing ? ( <> - {cleanBeforeEdit && ( + {effectiveClean && ( )} - {!cleanBeforeEdit && ( + {!effectiveClean && (