feat(k8s): M6 编辑器基础设施 + 基本信息 Tab + YAML编辑器
- DeploymentWorkload: 三模式切换(查看/编辑/YAML编辑)+ EditModeContainer Tab 导航系统 - DeploymentEditBasic: 新增基本信息 Tab — replicas/labels/annotations/selector 编辑 - YamlViewer: 升级为 CodeMirror 6(语法高亮+行号+折叠+括号匹配),新增 inline 内联模式 - DeploymentDetailPage: mode 类型扩展为 view|edit|yaml - 路由 :mode 参数自动支持 yaml 值 - M7-M9 Tab 预留占位(容器信息/存储/高级/服务)
This commit is contained in:
1 parent
2e66908e20
commit
68a954c1c5
9 files changed
+855
-42
No files matched your search
@@ -1,6 +1,6 @@
|
||||
// DeploymentWorkload.tsx — Kuboard 风格 Deployment 详情主组件
|
||||
// - 顶部操作菜单: 编辑 | 预览/编辑YAML | 调整镜像版本 | 伸缩 | 日志/终端 | 重启 | 暂停/恢复更新 | CI/CD发布 | 删除 | 元数据 | 运行时 | 服务 | 应用路由
|
||||
// - 双模式: view(只读增强看板)/ edit(表单编辑器)
|
||||
// - 三模式: view(只读增强看板)/ edit(可视化编辑器)/ yaml(YAML编辑器)
|
||||
// 作者: Logan <admin@attacker.club>
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
Trash2, FileText, Terminal, RefreshCw, Loader2, X,
|
||||
ChevronDown, Cpu, Network, GitBranch, Info,
|
||||
CheckCircle, AlertTriangle, XCircle,
|
||||
Pause, Play, Rocket,
|
||||
Pause, Play, Rocket, Container, Settings,
|
||||
} from 'lucide-react';
|
||||
import { kubernetesApi } from '@/services/api';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
@@ -25,16 +25,19 @@ import { useUserStore } from '@/store';
|
||||
import { YamlViewer } from './YamlViewer';
|
||||
import { DeploymentView } from './DeploymentView';
|
||||
import { DeploymentEdit } from './DeploymentEdit';
|
||||
import { DeploymentEditBasic } from './DeploymentEditBasic';
|
||||
|
||||
type WorkloadMode = 'view' | 'edit' | 'yaml';
|
||||
|
||||
export interface DeploymentWorkloadProps {
|
||||
clusterCode: string;
|
||||
namespace: string;
|
||||
deploymentName: string;
|
||||
/** 'view' | 'edit' — 来自路由参数 */
|
||||
mode: 'view' | 'edit';
|
||||
/** 'view' | 'edit' | 'yaml' — 来自路由参数 */
|
||||
mode: WorkloadMode;
|
||||
onBack: () => void;
|
||||
/** 跳转到另一模式(用于"编辑"按钮、保存成功后切换) */
|
||||
onModeChange: (mode: 'view' | 'edit') => void;
|
||||
onModeChange: (mode: WorkloadMode) => void;
|
||||
}
|
||||
|
||||
type ActionModal =
|
||||
@@ -287,7 +290,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{/* 模式切换 Tab */}
|
||||
{/* 模式切换 Tab — 三模式:查看 / 编辑 / YAML */}
|
||||
<div className="inline-flex rounded-md border border-slate-700 overflow-hidden">
|
||||
<button
|
||||
className={`px-3 py-1.5 text-xs font-medium transition-colors ${mode === 'view' ? 'bg-slate-700 text-slate-100' : 'bg-transparent text-slate-400 hover:text-slate-200'}`}
|
||||
@@ -301,6 +304,12 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
>
|
||||
<Pencil className="h-3 w-3 inline mr-1" />编辑模式
|
||||
</button>
|
||||
<button
|
||||
className={`px-3 py-1.5 text-xs font-medium transition-colors ${mode === 'yaml' ? 'bg-emerald-600 text-white' : 'bg-transparent text-slate-400 hover:text-slate-200'}`}
|
||||
onClick={() => onModeChange('yaml')}
|
||||
>
|
||||
<FileCode className="h-3 w-3 inline mr-1" />YAML编辑
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Button variant="outline" size="sm" className="border-slate-700 text-slate-400" onClick={loadData} title="刷新">
|
||||
@@ -372,7 +381,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ============ 主体:view / edit ============ */}
|
||||
{/* ============ 主体:view / edit / yaml ============ */}
|
||||
{mode === 'view' ? (
|
||||
<DeploymentView
|
||||
clusterCode={clusterCode}
|
||||
@@ -386,8 +395,21 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
onShowPodTerminal={handleShowPodTerminal}
|
||||
onShowPodYaml={handleShowPodYaml}
|
||||
/>
|
||||
) : mode === 'yaml' ? (
|
||||
/* YAML 编辑模式 — 内联 CodeMirror 编辑器 */
|
||||
<YamlViewer
|
||||
clusterCode={clusterCode}
|
||||
namespace={namespace}
|
||||
resource="deployments"
|
||||
name={deploymentName}
|
||||
cleanBeforeEdit
|
||||
inline
|
||||
onSaved={loadData}
|
||||
onClose={() => onModeChange('view')}
|
||||
/>
|
||||
) : (
|
||||
<DeploymentEdit
|
||||
/* 可视化编辑模式 — Tab 系统 */
|
||||
<EditModeContainer
|
||||
clusterCode={clusterCode}
|
||||
namespace={namespace}
|
||||
deploymentName={deploymentName}
|
||||
@@ -513,6 +535,83 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
);
|
||||
}
|
||||
|
||||
// ============ 编辑模式 Tab 容器(M6: 基本信息Tab + 容器编辑预留) ============
|
||||
function EditModeContainer({ clusterCode, namespace, deploymentName, manifest, onSaved, onCancel }: {
|
||||
clusterCode: string;
|
||||
namespace: string;
|
||||
deploymentName: string;
|
||||
manifest: any | null;
|
||||
onSaved: () => void;
|
||||
onCancel: () => void;
|
||||
}) {
|
||||
type EditTab = 'basic' | 'containers' | 'storage' | 'advanced' | 'service';
|
||||
const [activeTab, setActiveTab] = useState<EditTab>('basic');
|
||||
|
||||
const tabs: Array<{ key: EditTab; label: string; icon: typeof Settings; available: boolean; badge?: string }> = [
|
||||
{ key: 'basic', label: '基本信息', icon: Settings, available: true },
|
||||
{ key: 'containers', label: '容器信息', icon: Container, available: true, badge: 'M7' },
|
||||
{ key: 'storage', label: '存储挂载', icon: Container, available: false, badge: 'M8' },
|
||||
{ key: 'advanced', label: '高级设置', icon: Settings, available: false, badge: 'M8' },
|
||||
{ key: 'service', label: '服务/应用路由', icon: Network, available: false, badge: 'M9' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Tab 导航 */}
|
||||
<div className="flex items-center gap-1 border-b border-slate-800 pb-px overflow-x-auto">
|
||||
{tabs.map(tab => {
|
||||
const active = activeTab === tab.key;
|
||||
const Icon = tab.icon;
|
||||
return (
|
||||
<button
|
||||
key={tab.key}
|
||||
disabled={!tab.available}
|
||||
onClick={() => tab.available && setActiveTab(tab.key)}
|
||||
className={`flex items-center gap-1.5 px-3 py-2 text-xs font-medium border-b-2 transition-colors whitespace-nowrap
|
||||
${active
|
||||
? 'border-blue-500 text-blue-400'
|
||||
: tab.available
|
||||
? 'border-transparent text-slate-400 hover:text-slate-200'
|
||||
: 'border-transparent text-slate-600 cursor-not-allowed'
|
||||
}`}
|
||||
>
|
||||
<Icon className="h-3.5 w-3.5" />
|
||||
{tab.label}
|
||||
{tab.badge && (
|
||||
<span className={`text-[9px] px-1 py-0.5 rounded ${active ? 'bg-blue-500/20 text-blue-300' : 'bg-slate-800 text-slate-600'}`}>
|
||||
{tab.badge}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Tab 内容 */}
|
||||
{activeTab === 'basic' ? (
|
||||
<DeploymentEditBasic
|
||||
clusterCode={clusterCode}
|
||||
namespace={namespace}
|
||||
deploymentName={deploymentName}
|
||||
manifest={manifest}
|
||||
onSaved={onSaved}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
) : activeTab === 'containers' ? (
|
||||
/* M7 预留:容器编辑 — 暂用旧 DeploymentEdit */
|
||||
<DeploymentEdit
|
||||
clusterCode={clusterCode}
|
||||
namespace={namespace}
|
||||
deploymentName={deploymentName}
|
||||
manifest={manifest}
|
||||
onSaved={onSaved}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ============ 通用 Modal 外壳 ============
|
||||
function ModalShell({ title, children, onClose }: { title: string; children: React.ReactNode; onClose: () => void }) {
|
||||
return (
|
||||
|
||||
Reference in new issue
Block a user