diff --git a/backend/internal/database/database.go b/backend/internal/database/database.go
index e67ca6e..f098dc6 100644
--- a/backend/internal/database/database.go
+++ b/backend/internal/database/database.go
@@ -203,9 +203,9 @@ func seedResources() {
if n == 0 {
hb := time.Now().Add(-10 * time.Second)
DB.Create([]model.BuildNode{
- {Name: "build-host-01", IP: "10.0.8.11", Labels: `["docker","go","java"]`, MaxConcurrency: 4, Status: "online", CurrentJobs: 1, LastHeartbeat: &hb},
- {Name: "build-host-02", IP: "10.0.8.12", Labels: `["docker","nodejs"]`, MaxConcurrency: 2, Status: "busy", CurrentJobs: 2, LastHeartbeat: &hb},
- {Name: "build-host-03", IP: "10.0.8.13", Labels: `["python"]`, MaxConcurrency: 2, Status: "offline", LastHeartbeat: &hb},
+ {Name: "build-host-01", IP: "10.0.8.11", Labels: `["docker","go","java"]`, MaxConcurrency: 4, Status: "online", CurrentJobs: 1, DiskInfo: "78G/200G", LastHeartbeat: &hb},
+ {Name: "build-host-02", IP: "10.0.8.12", Labels: `["docker","nodejs"]`, MaxConcurrency: 2, Status: "busy", CurrentJobs: 2, DiskInfo: "156G/500G", LastHeartbeat: &hb},
+ {Name: "build-host-03", IP: "10.0.8.13", Labels: `["python"]`, MaxConcurrency: 2, Status: "offline", DiskInfo: "45G/100G", LastHeartbeat: &hb},
})
}
DB.Model(&model.WebhookEndpoint{}).Count(&n)
diff --git a/backend/internal/handler/resources.go b/backend/internal/handler/resources.go
index 3ab17ae..f9c1b1f 100644
--- a/backend/internal/handler/resources.go
+++ b/backend/internal/handler/resources.go
@@ -394,7 +394,7 @@ func UpdateBuildNode(c *gin.Context) {
}
var raw map[string]any
_ = c.ShouldBindJSON(&raw)
- for _, k := range []string{"name", "ip", "labels", "maxConcurrency", "workspacePath", "enabled"} {
+ for _, k := range []string{"name", "ip", "labels", "maxConcurrency", "workspacePath", "diskInfo", "enabled"} {
if v, ok := raw[k]; ok {
database.DB.Model(&n).Update(k, v)
}
diff --git a/backend/internal/model/models.go b/backend/internal/model/models.go
index 1107b5b..53b9991 100644
--- a/backend/internal/model/models.go
+++ b/backend/internal/model/models.go
@@ -204,6 +204,7 @@ type BuildNode struct {
Labels string `gorm:"type:text" json:"labels"` // JSON ["docker","go"]
MaxConcurrency int `gorm:"default:2" json:"maxConcurrency"`
WorkspacePath string `gorm:"default:/data/flowstack-workspace" json:"workspacePath"`
+ DiskInfo string `json:"diskInfo"` // 如 "45G/200G"
Enabled bool `gorm:"default:true" json:"enabled"`
Status string `gorm:"default:offline" json:"status"` // online|offline|busy
CurrentJobs int `gorm:"default:0" json:"currentJobs"`
diff --git a/frontend/index.html b/frontend/index.html
index ae53457..2947087 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -3,6 +3,7 @@
+
FlowStack · 发布系统
diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg
new file mode 100644
index 0000000..03a1a29
--- /dev/null
+++ b/frontend/public/favicon.svg
@@ -0,0 +1,15 @@
+
diff --git a/frontend/src/pages/BuildNodeManager.tsx b/frontend/src/pages/BuildNodeManager.tsx
index 6d399be..4be2425 100644
--- a/frontend/src/pages/BuildNodeManager.tsx
+++ b/frontend/src/pages/BuildNodeManager.tsx
@@ -10,6 +10,7 @@ import {
Trash2,
Tag,
Zap,
+ HardDrive,
} from 'lucide-react';
import { toast } from 'sonner';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
@@ -60,9 +61,10 @@ interface NodeForm {
labels: string;
maxConcurrency: string;
workspacePath: string;
+ diskInfo: string;
}
-const emptyForm: NodeForm = { name: '', ip: '', labels: '', maxConcurrency: '2', workspacePath: '/var/lib/flowstack/workspace' };
+const emptyForm: NodeForm = { name: '', ip: '', labels: '', maxConcurrency: '2', workspacePath: '/var/lib/flowstack/workspace', diskInfo: '' };
const inputStyle = {
background: 'var(--panel-bg-secondary)',
@@ -92,6 +94,7 @@ export default function BuildNodeManager() {
labels: parseJsonArray(node.labels).join(','),
maxConcurrency: String(node.maxConcurrency ?? 2),
workspacePath: node.workspacePath ?? '',
+ diskInfo: node.diskInfo ?? '',
}
: emptyForm,
);
@@ -152,6 +155,7 @@ export default function BuildNodeManager() {
labels: JSON.stringify(splitComma(form.labels)),
maxConcurrency: Number(form.maxConcurrency) || 1,
workspacePath: form.workspacePath.trim(),
+ diskInfo: form.diskInfo.trim(),
},
});
};
@@ -292,10 +296,16 @@ export default function BuildNodeManager() {
- {/* Info: 工作空间 / 心跳(后端暂无 CPU/内存/磁盘数据) */}
-
+ {/* Info: 磁盘 / 工作空间 / 心跳 */}
+
- 工作空间
+
+
+ {node.diskInfo || '—'}
+
+
+
+ 空间
{node.workspacePath || '—'}
@@ -366,6 +376,10 @@ export default function BuildNodeManager() {
setForm({ ...form, workspacePath: e.target.value })} placeholder="/var/lib/flowstack/workspace" />
+
+
+ setForm({ ...form, diskInfo: e.target.value })} placeholder="如 45G/200G(已用/总量)" />
+