refactor(frontend): P1-P2 架构统一 — utils/hooks/api 模块化
P1: - utils/storage.ts、theme.ts、validate.ts + index 统一出口 - request/store/useTheme 接入 storage;清零 confirm/alert - PipelineManager、TerminalAuditTab 拆分子模块(<700行红线) P2: - api/monitor、api/deploy 子目录化 - hooks/api 扩展:servers/pipelines/alerts/audit/sessionCommands - PipelineManager、AuditOperationsTab 接入 TanStack Query
This commit is contained in:
1 parent
d19a03d427
commit
f45e203e21
196 files changed
+3228
-2018
No files matched your search
@@ -35,6 +35,7 @@ import {
|
||||
|
||||
import { kubernetesApi } from '@/api';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
import { PodExecTerminal } from './PodExecTerminal';
|
||||
import { PodLogsViewer } from './PodLogsViewer';
|
||||
import { PodFileBrowser } from './PodFileBrowser';
|
||||
@@ -48,6 +49,7 @@ interface DeploymentDetailProps {
|
||||
|
||||
export function DeploymentDetail({ clusterCode, namespace, deploymentName, onBack }: DeploymentDetailProps) {
|
||||
const { toast } = useToast();
|
||||
const confirm = useConfirm();
|
||||
const [deployment, setDeployment] = useState<any>(null);
|
||||
const [pods, setPods] = useState<any[]>([]);
|
||||
const [hpas, setHpas] = useState<any[]>([]);
|
||||
@@ -174,7 +176,13 @@ export function DeploymentDetail({ clusterCode, namespace, deploymentName, onBac
|
||||
|
||||
const handleHpaToggle = async ( hpa: any) => {
|
||||
// Not direct toggle — delete HPA
|
||||
if (!confirm(`确定删除 HPA "${hpa.name}"?`)) return;
|
||||
const ok = await confirm({
|
||||
title: '删除 HPA',
|
||||
description: `确定删除 HPA "${hpa.name}"?`,
|
||||
confirmText: '删除',
|
||||
variant: 'destructive',
|
||||
});
|
||||
if (!ok) return;
|
||||
try {
|
||||
await kubernetesApi.deleteHPA(clusterCode, namespace, hpa.name);
|
||||
toast({ title: 'HPA 已删除' });
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
import { kubernetesApi } from '@/api';
|
||||
|
||||
interface Props {
|
||||
@@ -72,6 +73,7 @@ const toArray = ( v: any) => (Array.isArray(v) ? v : (v?.list || v?.items || v?.
|
||||
|
||||
export function DeploymentEditService({ clusterCode, namespace, deploymentName, manifest, onSaved, onCancel }: Props) {
|
||||
const { toast } = useToast();
|
||||
const confirm = useConfirm();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [services, setServices] = useState<SvcSummary[]>([]);
|
||||
const [ingresses, setIngresses] = useState<IngSummary[]>([]);
|
||||
@@ -265,7 +267,13 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
|
||||
|
||||
// 删除资源
|
||||
const deleteResource = async (kind: 'service' | 'ingress', name: string) => {
|
||||
if (!window.confirm(`确认删除 ${kind === 'service' ? 'Service' : 'Ingress'} 「${name}」?此操作不可撤销。`)) return;
|
||||
const ok = await confirm({
|
||||
title: '删除资源',
|
||||
description: `确认删除 ${kind === 'service' ? 'Service' : 'Ingress'} 「${name}」?此操作不可撤销。`,
|
||||
confirmText: '删除',
|
||||
variant: 'destructive',
|
||||
});
|
||||
if (!ok) return;
|
||||
try {
|
||||
const resource = kind === 'service' ? 'services' : 'ingresses';
|
||||
await kubernetesApi.deleteResourceYaml(clusterCode, namespace, resource, name);
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
|
||||
import { kubernetesApi } from '@/api';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
import {
|
||||
formatK8sTime, formatDuration, elapsedSeconds, statusColor, STATUS_COLORS,
|
||||
} from './k8s-yaml-utils';
|
||||
@@ -76,6 +77,7 @@ function getPodTimeline(pod: PodItem) {
|
||||
export function DeploymentView(props: DeploymentViewProps) {
|
||||
const { clusterCode, namespace, deployment, pods, revisions, onRefresh } = props;
|
||||
const { toast } = useToast();
|
||||
const confirm = useConfirm();
|
||||
const [tab, setTab] = useState('pods');
|
||||
const [expandedPod, setExpandedPod] = useState<string | null>(null);
|
||||
const [rollbackLoading, setRollbackLoading] = useState<number | null>(null);
|
||||
@@ -190,7 +192,13 @@ export function DeploymentView(props: DeploymentViewProps) {
|
||||
// Rollback
|
||||
const handleRollback = async ( rev: any) => {
|
||||
const revision = rev.revision ?? rev.revision_number ?? rev.number;
|
||||
if (!confirm(`确认回滚到修订版本 #${revision}?`)) return;
|
||||
const ok = await confirm({
|
||||
title: '回滚版本',
|
||||
description: `确认回滚到修订版本 #${revision}?`,
|
||||
confirmText: '回滚',
|
||||
variant: 'destructive',
|
||||
});
|
||||
if (!ok) return;
|
||||
setRollbackLoading(revision);
|
||||
try {
|
||||
await kubernetesApi.rollbackDeployment(clusterCode, namespace, deployment.name, Number(revision));
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
|
||||
import { kubernetesApi } from '@/api';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
import { useUserStore } from '@/store';
|
||||
import { YamlViewer } from './YamlViewer';
|
||||
import { DeploymentView } from './DeploymentView';
|
||||
@@ -73,6 +74,7 @@ type ActionModal =
|
||||
export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mode, onBack, onModeChange }: DeploymentWorkloadProps) {
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const confirm = useConfirm();
|
||||
const [deployment, setDeployment] = useState<any>(null);
|
||||
const [manifest, setManifest] = useState<any>(null);
|
||||
const [pods, setPods] = useState<any[]>([]);
|
||||
@@ -180,7 +182,12 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
};
|
||||
|
||||
const handleRestart = async () => {
|
||||
if (!confirm(`确认滚动重启 Deployment "${deploymentName}"?`)) return;
|
||||
const ok = await confirm({
|
||||
title: '滚动重启',
|
||||
description: `确认滚动重启 Deployment "${deploymentName}"?`,
|
||||
confirmText: '重启',
|
||||
});
|
||||
if (!ok) return;
|
||||
setActionLoading('restart');
|
||||
try {
|
||||
await kubernetesApi.restartDeployment(clusterCode, namespace, deploymentName);
|
||||
@@ -194,7 +201,12 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
const handleTogglePause = async () => {
|
||||
const isPaused = !!deployment?.paused;
|
||||
const action = isPaused ? '恢复' : '暂停';
|
||||
if (!confirm(`确认${action} Deployment "${deploymentName}" 的滚动更新?`)) return;
|
||||
const ok = await confirm({
|
||||
title: `${action}滚动更新`,
|
||||
description: `确认${action} Deployment "${deploymentName}" 的滚动更新?`,
|
||||
confirmText: action,
|
||||
});
|
||||
if (!ok) return;
|
||||
setActionLoading(isPaused ? 'resume' : 'pause');
|
||||
try {
|
||||
if (isPaused) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
Shield, Activity, AlertTriangle, CheckCircle2,
|
||||
} from 'lucide-react';
|
||||
import { kubernetesApi } from '@/api';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
interface NamespaceDetail {
|
||||
name: string;
|
||||
@@ -75,7 +76,7 @@ export default function NamespaceManagementPage() {
|
||||
setCreateOpen(false);
|
||||
await loadData();
|
||||
} catch (err: any) {
|
||||
alert(err?.message || '创建失败');
|
||||
toast.error(err?.message || '创建失败');
|
||||
} finally {
|
||||
setCreating(false);
|
||||
}
|
||||
@@ -89,7 +90,7 @@ export default function NamespaceManagementPage() {
|
||||
setDeleteTarget(null);
|
||||
await loadData();
|
||||
} catch (err: any) {
|
||||
alert(err?.message || '删除失败');
|
||||
toast.error(err?.message || '删除失败');
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { kubernetesApi } from '@/api';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
import { YamlViewer } from './YamlViewer';
|
||||
import { PodExecTerminal } from './PodExecTerminal';
|
||||
import { PodFileBrowser } from './PodFileBrowser';
|
||||
@@ -55,6 +56,7 @@ export default function WorkloadViewPage() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { toast } = useToast();
|
||||
const confirm = useConfirm();
|
||||
|
||||
const clusterCode = params.clusterCode || '';
|
||||
const namespace = params.namespace || '';
|
||||
@@ -114,7 +116,12 @@ export default function WorkloadViewPage() {
|
||||
};
|
||||
|
||||
const handleRestart = async () => {
|
||||
if (!confirm(`确认重启 ${kind} ${name}?\n将触发滚动重启。`)) return;
|
||||
const ok = await confirm({
|
||||
title: '滚动重启',
|
||||
description: `确认重启 ${kind} ${name}?将触发滚动重启。`,
|
||||
confirmText: '重启',
|
||||
});
|
||||
if (!ok) return;
|
||||
setActionLoading(true);
|
||||
try {
|
||||
if (kind === 'StatefulSet') {
|
||||
|
||||
@@ -15,11 +15,13 @@ import {
|
||||
|
||||
import { ContainerEditor } from './ContainerEditor';
|
||||
import type { ContainerGroupSectionProps } from './types';
|
||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||
|
||||
export function ContainerGroupSection({
|
||||
title, description, icon, containers, accentColor,
|
||||
onAdd, onRemove, onUpdate, onDuplicate,
|
||||
}: ContainerGroupSectionProps) {
|
||||
const confirm = useConfirm();
|
||||
const [openIndices, setOpenIndices] = useState<Set<number>>(new Set([0]));
|
||||
const toggleOpen = (idx: number) => {
|
||||
setOpenIndices(prev => {
|
||||
@@ -70,7 +72,15 @@ export function ContainerGroupSection({
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 text-red-400 hover:text-red-300" title="删除"
|
||||
onClick={() => { if (confirm(`确认删除容器「${c.name}」?`)) onRemove(idx); }}>
|
||||
onClick={async () => {
|
||||
const ok = await confirm({
|
||||
title: '删除容器',
|
||||
description: `确认删除容器「${c.name}」?`,
|
||||
confirmText: '删除',
|
||||
variant: 'destructive',
|
||||
});
|
||||
if (ok) onRemove(idx);
|
||||
}}>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user