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
|
// PUT /api/v1/instance-groups/:id
|
||||||
func UpdateInstanceGroup(c *gin.Context) {
|
func UpdateInstanceGroup(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
|
gid, _ := strconv.Atoi(id)
|
||||||
var group model.InstanceGroup
|
var group model.InstanceGroup
|
||||||
if err := model.DB.First(&group, id).Error; err != nil {
|
if err := model.DB.First(&group, id).Error; err != nil {
|
||||||
c.JSON(http.StatusNotFound, gin.H{"detail": "Instance group not found"})
|
c.JSON(http.StatusNotFound, gin.H{"detail": "Instance group not found"})
|
||||||
@@ -47,14 +48,16 @@ func UpdateInstanceGroup(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var input struct {
|
var input struct {
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
DBType *string `json:"db_type"`
|
DBType *string `json:"db_type"`
|
||||||
Permissions *string `json:"permissions"`
|
Permissions *string `json:"permissions"`
|
||||||
IsActive *bool `json:"is_active"`
|
IsActive *bool `json:"is_active"`
|
||||||
WorkflowID *int `json:"workflow_id"`
|
WorkflowID *int `json:"workflow_id"`
|
||||||
AccessType *string `json:"access_type"`
|
AccessType *string `json:"access_type"`
|
||||||
AllowedDatabases *string `json:"allowed_databases"`
|
AllowedDatabases *string `json:"allowed_databases"`
|
||||||
|
ReadonlyInstanceIDs *[]int `json:"readonly_instance_ids"`
|
||||||
|
WriteInstanceIDs *[]int `json:"write_instance_ids"`
|
||||||
}
|
}
|
||||||
if err := c.ShouldBindJSON(&input); err != nil {
|
if err := c.ShouldBindJSON(&input); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||||
@@ -87,14 +90,41 @@ func UpdateInstanceGroup(c *gin.Context) {
|
|||||||
updates["allowed_databases"] = *input.AllowedDatabases
|
updates["allowed_databases"] = *input.AllowedDatabases
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(updates) == 0 {
|
if len(updates) > 0 {
|
||||||
c.JSON(http.StatusOK, enrichGroup(group))
|
if err := model.DB.Model(&group).Updates(updates).Error; err != nil {
|
||||||
return
|
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := model.DB.Model(&group).Updates(updates).Error; err != nil {
|
// Update instance members if provided
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
if input.ReadonlyInstanceIDs != nil || input.WriteInstanceIDs != nil {
|
||||||
return
|
// 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)
|
model.DB.First(&group, id)
|
||||||
@@ -263,19 +293,33 @@ func enrichGroup(group model.InstanceGroup) gin.H {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return gin.H{
|
return gin.H{
|
||||||
"id": group.ID,
|
"id": group.ID,
|
||||||
"name": group.Name,
|
"name": group.Name,
|
||||||
"description": group.Description,
|
"description": group.Description,
|
||||||
"db_type": group.DBType,
|
"db_type": group.DBType,
|
||||||
"permissions": group.Permissions,
|
"permissions": group.Permissions,
|
||||||
"is_active": group.IsActive,
|
"is_active": group.IsActive,
|
||||||
"created_at": group.CreatedAt,
|
"created_at": group.CreatedAt,
|
||||||
"updated_at": group.UpdatedAt,
|
"updated_at": group.UpdatedAt,
|
||||||
"workflow_id": group.WorkflowID,
|
"workflow_id": group.WorkflowID,
|
||||||
"access_type": group.AccessType,
|
"access_type": group.AccessType,
|
||||||
"allowed_databases": group.AllowedDatabases,
|
"allowed_databases": group.AllowedDatabases,
|
||||||
"readonly_instance_count": readonlyCount,
|
"readonly_instance_count": readonlyCount,
|
||||||
"write_instance_count": writeCount,
|
"write_instance_count": writeCount,
|
||||||
"user_count": userCount,
|
"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">
|
<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) => {
|
{(wf.steps || []).map((step, i) => {
|
||||||
const StepIcon = STEP_TYPE_ICONS[step.step_type] || Shield;
|
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 || [];
|
const stepsArr = wf.steps || [];
|
||||||
return (
|
return (
|
||||||
<div key={step.id || i} className="flex items-center gap-1 flex-shrink-0">
|
<div key={step.id || i} className="flex items-center gap-1 flex-shrink-0">
|
||||||
|
|||||||
Reference in new issue
Block a user