fix: 实例分组编辑保存实例关联 — UpdateInstanceGroup 接收 readonly/write_instance_ids
- UpdateInstanceGroup 新增 readonly_instance_ids/write_instance_ids 字段处理 - 清除旧成员后重新写入 instance_group_members 表 - enrichGroup 返回 readonly_instance_ids/write_instance_ids 供前端穿梭框回显 - 新增 collectInstanceIDs helper 去重提取 ID 列表
This commit is contained in:
1 parent
2957075345
commit
e5af40466c
2 files changed
+73
-28
No files matched your search
@@ -40,6 +40,7 @@ func CreateInstanceGroup(c *gin.Context) {
|
||||
// PUT /api/v1/instance-groups/:id
|
||||
func UpdateInstanceGroup(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
gid, _ := strconv.Atoi(id)
|
||||
var group model.InstanceGroup
|
||||
if err := model.DB.First(&group, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"detail": "Instance group not found"})
|
||||
@@ -47,14 +48,16 @@ func UpdateInstanceGroup(c *gin.Context) {
|
||||
}
|
||||
|
||||
var input struct {
|
||||
Name *string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
DBType *string `json:"db_type"`
|
||||
Permissions *string `json:"permissions"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
AccessType *string `json:"access_type"`
|
||||
AllowedDatabases *string `json:"allowed_databases"`
|
||||
Name *string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
DBType *string `json:"db_type"`
|
||||
Permissions *string `json:"permissions"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
AccessType *string `json:"access_type"`
|
||||
AllowedDatabases *string `json:"allowed_databases"`
|
||||
ReadonlyInstanceIDs *[]int `json:"readonly_instance_ids"`
|
||||
WriteInstanceIDs *[]int `json:"write_instance_ids"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
@@ -87,14 +90,41 @@ func UpdateInstanceGroup(c *gin.Context) {
|
||||
updates["allowed_databases"] = *input.AllowedDatabases
|
||||
}
|
||||
|
||||
if len(updates) == 0 {
|
||||
c.JSON(http.StatusOK, enrichGroup(group))
|
||||
return
|
||||
if len(updates) > 0 {
|
||||
if err := model.DB.Model(&group).Updates(updates).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := model.DB.Model(&group).Updates(updates).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
||||
return
|
||||
// Update instance members if provided
|
||||
if input.ReadonlyInstanceIDs != nil || input.WriteInstanceIDs != nil {
|
||||
// Clear all existing members for this group
|
||||
model.DB.Where("group_id = ?", gid).Delete(&model.InstanceGroupMember{})
|
||||
|
||||
// Add readonly instances
|
||||
if input.ReadonlyInstanceIDs != nil {
|
||||
for _, iid := range *input.ReadonlyInstanceIDs {
|
||||
member := model.InstanceGroupMember{
|
||||
GroupID: gid,
|
||||
InstanceID: iid,
|
||||
AccessType: "readonly",
|
||||
}
|
||||
model.DB.Create(&member)
|
||||
}
|
||||
}
|
||||
|
||||
// Add write instances
|
||||
if input.WriteInstanceIDs != nil {
|
||||
for _, iid := range *input.WriteInstanceIDs {
|
||||
member := model.InstanceGroupMember{
|
||||
GroupID: gid,
|
||||
InstanceID: iid,
|
||||
AccessType: "write",
|
||||
}
|
||||
model.DB.Create(&member)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model.DB.First(&group, id)
|
||||
@@ -263,19 +293,33 @@ func enrichGroup(group model.InstanceGroup) gin.H {
|
||||
}
|
||||
|
||||
return gin.H{
|
||||
"id": group.ID,
|
||||
"name": group.Name,
|
||||
"description": group.Description,
|
||||
"db_type": group.DBType,
|
||||
"permissions": group.Permissions,
|
||||
"is_active": group.IsActive,
|
||||
"created_at": group.CreatedAt,
|
||||
"updated_at": group.UpdatedAt,
|
||||
"workflow_id": group.WorkflowID,
|
||||
"access_type": group.AccessType,
|
||||
"allowed_databases": group.AllowedDatabases,
|
||||
"id": group.ID,
|
||||
"name": group.Name,
|
||||
"description": group.Description,
|
||||
"db_type": group.DBType,
|
||||
"permissions": group.Permissions,
|
||||
"is_active": group.IsActive,
|
||||
"created_at": group.CreatedAt,
|
||||
"updated_at": group.UpdatedAt,
|
||||
"workflow_id": group.WorkflowID,
|
||||
"access_type": group.AccessType,
|
||||
"allowed_databases": group.AllowedDatabases,
|
||||
"readonly_instance_count": readonlyCount,
|
||||
"write_instance_count": writeCount,
|
||||
"user_count": userCount,
|
||||
"write_instance_count": writeCount,
|
||||
"user_count": userCount,
|
||||
"readonly_instance_ids": collectInstanceIDs(readonlyMembers),
|
||||
"write_instance_ids": collectInstanceIDs(writeMembers),
|
||||
}
|
||||
}
|
||||
|
||||
func collectInstanceIDs(members []model.InstanceGroupMember) []int {
|
||||
ids := []int{}
|
||||
seen := map[int]bool{}
|
||||
for _, m := range members {
|
||||
if !seen[m.InstanceID] {
|
||||
seen[m.InstanceID] = true
|
||||
ids = append(ids, m.InstanceID)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
@@ -635,7 +635,8 @@ export default function WorkflowPage() {
|
||||
<div className="flex items-center gap-1 mt-4 p-4 bg-[var(--dg-bg-tertiary)] rounded-lg overflow-x-auto">
|
||||
{(wf.steps || []).map((step, i) => {
|
||||
const StepIcon = STEP_TYPE_ICONS[step.step_type] || Shield;
|
||||
const uids: number[] = step.approver_ids ? JSON.parse(step.approver_ids) : [];
|
||||
let uids: number[] = [];
|
||||
try { const parsed = JSON.parse(step.approver_ids); if (Array.isArray(parsed)) uids = parsed; } catch {}
|
||||
const stepsArr = wf.steps || [];
|
||||
return (
|
||||
<div key={step.id || i} className="flex items-center gap-1 flex-shrink-0">
|
||||
|
||||
Reference in new issue
Block a user