DevOS v1 + Phase 2: unified resource model, infra ops, website deployment, AI chat ops

- Monorepo: NestJS API (Fastify) + React web (antd/ProComponents) + shared packages
- PostgreSQL/Prisma (unified resources, relations graph, audit, events, jobs)
- Auth/RBAC/workspace isolation, credential vault (AES-256-GCM)
- Servers/SSH, Docker discovery & lifecycle, Job Center
- Websites & deployments (git provider credential clone, env, health verification)
- Domains/DNS (Cloudflare adapter), certificates (TLS probe), monitoring
- Automation (cron/event/webhook HMAC + notifications), AI Gateway, MCP (29 tools)
- AI chat window (LLM function-calling + rules fallback, SSE streaming, approvals)
- Notes: Vditor WYSIWYG markdown editor, non-blocking autosave
- Tests: 35 unit/security tests; UI audit clean (desktop+mobile, deep links)
This commit is contained in:
phptits
2026-09-10 06:35:55 +00:00
commit 0d6cd37579
209 changed files with 22783 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
/**
* # 容器列表页(全工作区)
*/
import { useRef } from "react";
import {
PageContainer,
ProTable,
type ActionType,
type ProColumns,
} from "@ant-design/pro-components";
import { App as AntApp, Popconfirm } from "antd";
import { ReloadOutlined } from "@ant-design/icons";
import { containerApi } from "../services/api";
import type { ContainerView } from "@devos/types";
import { StatusBadge } from "../components/shared";
export default function ContainersPage() {
const { message } = AntApp.useApp();
const actionRef = useRef<ActionType>(null);
const columns: ProColumns<ContainerView>[] = [
{ title: "名称", dataIndex: "name" },
{ title: "镜像", dataIndex: "image", ellipsis: true },
{ title: "状态", dataIndex: "state", render: (_, r) => <StatusBadge status={r.state} /> },
{ title: "容器 ID", dataIndex: "containerId", copyable: true },
{
title: "操作",
valueType: "option",
render: (_, record) => [
<Popconfirm
key="restart"
title={`重启容器 ${record.name}?(HIGH 风险操作)`}
onConfirm={async () => {
try {
await containerApi.restart(record.id);
message.success("容器已重启");
actionRef.current?.reload();
} catch (e) {
message.error(e instanceof Error ? e.message : "失败");
}
}}
>
<a style={{ color: "#fa8c16" }}>
<ReloadOutlined /> 重启
</a>
</Popconfirm>,
],
},
];
return (
<PageContainer>
<ProTable<ContainerView>
scroll={{ x: "max-content" }}
rowKey="id"
columns={columns}
actionRef={actionRef}
headerTitle="容器"
search={false}
pagination={{ pageSize: 20 }}
request={async () => {
const items = await containerApi.list();
return { data: items, success: true, total: items.length };
}}
/>
</PageContainer>
);
}