From 6337d975eae39a97f954084d046a3e94cf383e8a Mon Sep 17 00:00:00 2001 From: chan Date: Wed, 25 Mar 2026 17:43:30 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20Admin=20UI=EC=97=90=EC=84=9C=20=EC=A0=84?= =?UTF-8?q?=EC=86=A1=ED=95=9C=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=95=84?= =?UTF-8?q?=EB=93=9C(metadata)=EA=B0=80=20=EB=B0=B1=EC=97=94=EB=93=9C=20Kr?= =?UTF-8?q?atos=20=ED=8A=B8=EB=A0=88=EC=9D=B4=EC=B8=A0=EC=97=90=20?= =?UTF-8?q?=EB=B9=88=20=EB=B0=B0=EC=97=B4=EB=A1=9C=20=EA=B9=A8=EC=A0=B8?= =?UTF-8?q?=EC=84=9C=20=EC=A0=80=EC=9E=A5=EB=90=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20(#440)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/users/UserDetailPage.tsx | 19 +++++++++++++++++-- backend/internal/handler/user_handler.go | 19 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/adminfront/src/features/users/UserDetailPage.tsx b/adminfront/src/features/users/UserDetailPage.tsx index 6db94a92..e526c619 100644 --- a/adminfront/src/features/users/UserDetailPage.tsx +++ b/adminfront/src/features/users/UserDetailPage.tsx @@ -139,7 +139,9 @@ function TenantMetadataFields({ ); } -type UserFormValues = UserUpdateRequest & { metadata: Record }; +type UserFormValues = Omit & { + metadata: Record>; +}; function UserDetailPage() { const params = useParams<{ id: string }>(); @@ -299,7 +301,20 @@ function UserDetailPage() { const onSubmit = (data: UserFormValues) => { setError(null); setSuccessMsg(null); - mutation.mutate(data); + + // Filter out undefined/null/empty strings from metadata + const cleanMetadata = Object.fromEntries( + Object.entries(data.metadata).map(([tenantId, fields]) => { + const cleanFields = Object.fromEntries( + Object.entries(fields).filter( + ([_, v]) => v !== undefined && v !== null && v !== "", + ), + ); + return [tenantId, cleanFields]; + }), + ); + + mutation.mutate({ ...data, metadata: cleanMetadata }); }; const handleDelete = () => { diff --git a/backend/internal/handler/user_handler.go b/backend/internal/handler/user_handler.go index 40d101f1..112b95bb 100644 --- a/backend/internal/handler/user_handler.go +++ b/backend/internal/handler/user_handler.go @@ -1194,15 +1194,28 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error { } // For namespaced metadata, we don't delete everything, we merge. - // But we should remove legacy flat traits that are not in the new req.Metadata if we want strict sync. - // For now, let's just merge. for k, v := range req.Metadata { if !coreTraits[k] { - traits[k] = v + // Ensure we are merging maps (tenant namespaces) correctly, not overwriting with slices + if incomingMap, ok := v.(map[string]any); ok { + if existingMap, ok := traits[k].(map[string]interface{}); ok { + for subK, subV := range incomingMap { + existingMap[subK] = subV + } + traits[k] = existingMap + } else { + traits[k] = incomingMap // New namespace + } + } else { + traits[k] = v // Fallback for flat metadata + } } } state := normalizeKratosState(req.Status) + + slog.Info("[UpdateUser] Calling Kratos UpdateIdentity", "userID", userID, "traits", traits, "state", state) + updated, err := h.KratosAdmin.UpdateIdentity(c.Context(), userID, traits, state) if err != nil { return errorJSON(c, fiber.StatusInternalServerError, err.Error())