forked from baron/baron-sso
조직 연동 오류 해결
This commit is contained in:
@@ -4,11 +4,14 @@ import {
|
||||
canCreateWorksmobileRow,
|
||||
canOpenWorksmobilePasswordManage,
|
||||
canSelectWorksmobileRow,
|
||||
comparisonFilterOptions,
|
||||
filterVisibleWorksmobileComparisonRows,
|
||||
filterWorksmobileComparisonRows,
|
||||
filterWorksmobileComparisonRowsBySearch,
|
||||
formatWorksmobileOrgDetails,
|
||||
formatWorksmobilePersonName,
|
||||
formatWorksmobileUpdateDetails,
|
||||
getDefaultGroupComparisonFilters,
|
||||
getDefaultWorksmobileComparisonColumns,
|
||||
getWorksmobileComparisonStatusLabel,
|
||||
getWorksmobileRowSelectionKey,
|
||||
@@ -24,6 +27,7 @@ describe("TenantWorksmobilePage comparison helpers", () => {
|
||||
it("summarizes comparison rows by status", () => {
|
||||
const summary = summarizeWorksmobileComparison([
|
||||
{ resourceType: "USER", status: "matched" },
|
||||
{ resourceType: "GROUP", status: "needs_update" },
|
||||
{ resourceType: "USER", status: "missing_in_worksmobile" },
|
||||
{ resourceType: "USER", status: "missing_in_baron" },
|
||||
{ resourceType: "USER", status: "missing_external_key" },
|
||||
@@ -31,8 +35,9 @@ describe("TenantWorksmobilePage comparison helpers", () => {
|
||||
]);
|
||||
|
||||
expect(summary).toEqual({
|
||||
total: 5,
|
||||
total: 6,
|
||||
matched: 1,
|
||||
needsUpdate: 1,
|
||||
missingInWorksmobile: 1,
|
||||
missingInBaron: 2,
|
||||
missingExternalKey: 1,
|
||||
@@ -50,6 +55,9 @@ describe("TenantWorksmobilePage comparison helpers", () => {
|
||||
expect(getWorksmobileComparisonStatusLabel("missing_external_key")).toBe(
|
||||
"ex_key 없음",
|
||||
);
|
||||
expect(getWorksmobileComparisonStatusLabel("needs_update")).toBe(
|
||||
"업데이트 필요",
|
||||
);
|
||||
expect(getWorksmobileComparisonStatusLabel("unknown_status")).toBe(
|
||||
"unknown_status",
|
||||
);
|
||||
@@ -426,11 +434,52 @@ describe("TenantWorksmobilePage comparison helpers", () => {
|
||||
it("orders user comparison filter options from Baron-only first", () => {
|
||||
expect(userFilterOptions.map((option) => option.value)).toEqual([
|
||||
"baron_only",
|
||||
"needs_update",
|
||||
"works_only",
|
||||
"matched",
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps all organization/group comparison filter labels available", () => {
|
||||
expect(comparisonFilterOptions).toEqual([
|
||||
{ value: "baron_only", label: "바론에만 있음" },
|
||||
{ value: "needs_update", label: "업데이트 필요" },
|
||||
{ value: "works_only", label: "웍스에만 있음" },
|
||||
{ value: "matched", label: "양쪽 다 있음" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("shows update-needed group rows by default", () => {
|
||||
const rows = [
|
||||
{ resourceType: "GROUP", status: "needs_update", baronId: "org-1" },
|
||||
{ resourceType: "GROUP", status: "matched", baronId: "org-2" },
|
||||
];
|
||||
|
||||
expect(
|
||||
filterWorksmobileComparisonRows(rows, getDefaultGroupComparisonFilters()),
|
||||
).toEqual([rows[0]]);
|
||||
});
|
||||
|
||||
it("formats update details for changed organization rows", () => {
|
||||
expect(
|
||||
formatWorksmobileUpdateDetails({
|
||||
resourceType: "GROUP",
|
||||
status: "needs_update",
|
||||
baronId: "818c856b-9545-442f-b827-d1c569f200b0",
|
||||
baronName: "삼안기술개발센터(조직도용)",
|
||||
worksmobileName: "기술개발센터(조직도용)",
|
||||
baronParentId: "9caf62e1-297d-4e8f-870b-61780998bbeb",
|
||||
baronParentWorksmobileId: "works-saman",
|
||||
baronParentWorksmobileName: "삼안",
|
||||
worksmobileParentId: "works-other",
|
||||
worksmobileParentName: "다른 상위",
|
||||
}),
|
||||
).toEqual([
|
||||
"이름: 기술개발센터(조직도용) -> 삼안기술개발센터(조직도용)",
|
||||
"상위: 다른 상위 -> 삼안",
|
||||
]);
|
||||
});
|
||||
|
||||
it("formats WORKS account name with level on one line", () => {
|
||||
expect(
|
||||
formatWorksmobilePersonName({
|
||||
|
||||
@@ -63,6 +63,8 @@ import {
|
||||
filterWorksmobileComparisonRowsBySearch,
|
||||
formatWorksmobileOrgDetails,
|
||||
formatWorksmobilePersonName,
|
||||
formatWorksmobileUpdateDetails,
|
||||
getDefaultGroupComparisonFilters,
|
||||
getDefaultWorksmobileComparisonColumns,
|
||||
getWorksmobileComparisonStatusLabel,
|
||||
getWorksmobileRowSelectionKey,
|
||||
@@ -81,7 +83,7 @@ export function TenantWorksmobilePage() {
|
||||
>(["baron_only", "works_only"]);
|
||||
const [groupFilters, setGroupFilters] = React.useState<
|
||||
WorksmobileComparisonFilter[]
|
||||
>(["baron_only", "works_only"]);
|
||||
>(getDefaultGroupComparisonFilters);
|
||||
const [includeUserMissingExternalKey, setIncludeUserMissingExternalKey] =
|
||||
React.useState(false);
|
||||
const [includeGroupMissingExternalKey, setIncludeGroupMissingExternalKey] =
|
||||
@@ -594,6 +596,9 @@ function getWorksmobileComparisonStatusVariant(status: string) {
|
||||
if (status === "matched") {
|
||||
return "success";
|
||||
}
|
||||
if (status === "needs_update") {
|
||||
return "warning";
|
||||
}
|
||||
if (status === "missing_external_key") {
|
||||
return "warning";
|
||||
}
|
||||
@@ -622,6 +627,10 @@ function ComparisonSummary({
|
||||
<span className="text-muted-foreground">Baron 없음</span>
|
||||
<span className="font-mono">{summary.missingInBaron}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">업데이트 필요</span>
|
||||
<span className="font-mono">{summary.needsUpdate}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">ex_key 없음</span>
|
||||
<span className="font-mono">{summary.missingExternalKey}</span>
|
||||
@@ -860,7 +869,7 @@ function ComparisonTable({
|
||||
return (
|
||||
<div className="min-w-0 space-y-2">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 flex-wrap items-center gap-3">
|
||||
<div className="flex min-w-0 flex-1 flex-wrap items-center gap-3">
|
||||
<h4 className="text-lg font-semibold leading-none">{title}</h4>
|
||||
<Input
|
||||
type="search"
|
||||
@@ -890,7 +899,7 @@ function ComparisonTable({
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-auto flex flex-wrap items-center justify-end gap-2">
|
||||
<div className="flex shrink-0 flex-wrap items-center justify-end gap-2">
|
||||
<Dialog
|
||||
open={columnSettingsOpen}
|
||||
onOpenChange={setColumnSettingsOpen}
|
||||
@@ -1058,6 +1067,14 @@ function ComparisonTable({
|
||||
>
|
||||
{getWorksmobileComparisonStatusLabel(row.status)}
|
||||
</Badge>
|
||||
{formatWorksmobileUpdateDetails(row).map((detail) => (
|
||||
<div
|
||||
key={detail}
|
||||
className="mt-1 max-w-56 whitespace-normal text-xs text-muted-foreground"
|
||||
>
|
||||
{detail}
|
||||
</div>
|
||||
))}
|
||||
</TableCell>
|
||||
)}
|
||||
{showBaronIdColumn && isColumnVisible("baronId") && (
|
||||
|
||||
@@ -3,11 +3,13 @@ import type { WorksmobileComparisonItem } from "../../../lib/adminApi";
|
||||
export type WorksmobileComparisonFilter =
|
||||
| "works_only"
|
||||
| "baron_only"
|
||||
| "needs_update"
|
||||
| "matched";
|
||||
|
||||
export type WorksmobileComparisonSummary = {
|
||||
total: number;
|
||||
matched: number;
|
||||
needsUpdate: number;
|
||||
missingInWorksmobile: number;
|
||||
missingInBaron: number;
|
||||
missingExternalKey: number;
|
||||
@@ -52,6 +54,8 @@ export function summarizeWorksmobileComparison(
|
||||
(summary, row) => {
|
||||
if (row.status === "matched") {
|
||||
summary.matched += 1;
|
||||
} else if (row.status === "needs_update") {
|
||||
summary.needsUpdate += 1;
|
||||
} else if (row.status === "missing_in_worksmobile") {
|
||||
summary.missingInWorksmobile += 1;
|
||||
} else if (row.status === "missing_in_baron") {
|
||||
@@ -64,6 +68,7 @@ export function summarizeWorksmobileComparison(
|
||||
{
|
||||
total: rows.length,
|
||||
matched: 0,
|
||||
needsUpdate: 0,
|
||||
missingInWorksmobile: 0,
|
||||
missingInBaron: 0,
|
||||
missingExternalKey: 0,
|
||||
@@ -77,6 +82,8 @@ export function getWorksmobileComparisonStatusLabel(status: string) {
|
||||
return "일치";
|
||||
case "missing_in_worksmobile":
|
||||
return "WORKS 없음";
|
||||
case "needs_update":
|
||||
return "업데이트 필요";
|
||||
case "missing_in_baron":
|
||||
return "Baron 없음";
|
||||
case "missing_external_key":
|
||||
@@ -292,6 +299,42 @@ export function formatWorksmobileOrgDetails(row: WorksmobileComparisonItem) {
|
||||
return details;
|
||||
}
|
||||
|
||||
export function formatWorksmobileUpdateDetails(row: WorksmobileComparisonItem) {
|
||||
if (row.status !== "needs_update") {
|
||||
return [];
|
||||
}
|
||||
|
||||
const details: string[] = [];
|
||||
const baronName = row.baronName?.trim();
|
||||
const worksmobileName = row.worksmobileName?.trim();
|
||||
if (baronName && worksmobileName && baronName !== worksmobileName) {
|
||||
details.push(`이름: ${worksmobileName} -> ${baronName}`);
|
||||
}
|
||||
|
||||
const expectedParent =
|
||||
row.baronParentWorksmobileName ??
|
||||
row.baronParentName ??
|
||||
row.baronParentWorksmobileId ??
|
||||
row.baronParentId ??
|
||||
"";
|
||||
const actualParent =
|
||||
row.worksmobileParentName ??
|
||||
row.worksmobileParentExternalKey ??
|
||||
row.worksmobileParentId ??
|
||||
"";
|
||||
const expectedParentKey =
|
||||
row.baronParentWorksmobileId ?? row.baronParentId ?? "";
|
||||
const actualParentKey =
|
||||
row.worksmobileParentId ?? row.worksmobileParentExternalKey ?? "";
|
||||
if (expectedParentKey !== actualParentKey) {
|
||||
details.push(
|
||||
`상위: ${actualParent || "없음"} -> ${expectedParent || "없음"}`,
|
||||
);
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
export function buildWorksmobilePasswordManageUrl({
|
||||
tenantId,
|
||||
domainId,
|
||||
@@ -345,15 +388,21 @@ export const comparisonFilterOptions: Array<{
|
||||
label: string;
|
||||
}> = [
|
||||
{ value: "baron_only", label: "바론에만 있음" },
|
||||
{ value: "needs_update", label: "업데이트 필요" },
|
||||
{ value: "works_only", label: "웍스에만 있음" },
|
||||
{ value: "matched", label: "양쪽 다 있음" },
|
||||
];
|
||||
|
||||
export const userFilterOptions = comparisonFilterOptions;
|
||||
|
||||
export function getDefaultGroupComparisonFilters(): WorksmobileComparisonFilter[] {
|
||||
return ["baron_only", "needs_update", "works_only"];
|
||||
}
|
||||
|
||||
const worksmobileFilterStatuses: Record<WorksmobileComparisonFilter, string[]> =
|
||||
{
|
||||
baron_only: ["missing_in_worksmobile"],
|
||||
needs_update: ["needs_update"],
|
||||
works_only: ["missing_in_baron"],
|
||||
matched: ["matched"],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user