forked from baron/baron-sso
동기화 기초구조 마련
This commit is contained in:
54
orgfront/src/features/orgchart/hanmacFamilyOrder.test.ts
Normal file
54
orgfront/src/features/orgchart/hanmacFamilyOrder.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
getHanmacFamilyTenantOrderRank,
|
||||
orderHanmacFamilyChildren,
|
||||
orderHanmacFamilyTenants,
|
||||
} from "./hanmacFamilyOrder";
|
||||
|
||||
function tenant(name: string, slug: string) {
|
||||
return { name, slug };
|
||||
}
|
||||
|
||||
describe("hanmac family organization order", () => {
|
||||
it("orders the top hanmac-family siblings by policy", () => {
|
||||
const ordered = orderHanmacFamilyTenants([
|
||||
tenant("바론그룹", "baron-group"),
|
||||
tenant("한맥기술", "hanmac"),
|
||||
tenant("삼안", "saman"),
|
||||
tenant("총괄기획&기술개발센터", "gpdtdc"),
|
||||
]);
|
||||
|
||||
expect(ordered.map((item) => item.name)).toEqual([
|
||||
"총괄기획&기술개발센터",
|
||||
"삼안",
|
||||
"한맥기술",
|
||||
"바론그룹",
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps hanmac-family as the root before ordered descendants", () => {
|
||||
const family = tenant("한맥가족", "hanmac-family");
|
||||
const children = orderHanmacFamilyChildren(family, [
|
||||
tenant("바론그룹", "baron-group"),
|
||||
tenant("총괄기획&기술개발센터", "gpdtdc"),
|
||||
tenant("삼안", "saman"),
|
||||
tenant("한맥기술", "hanmac"),
|
||||
]);
|
||||
|
||||
expect([family, ...children].map((item) => item.name)).toEqual([
|
||||
"한맥가족",
|
||||
"총괄기획&기술개발센터",
|
||||
"삼안",
|
||||
"한맥기술",
|
||||
"바론그룹",
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not rank generic technical centers as GPDTDC", () => {
|
||||
expect(
|
||||
getHanmacFamilyTenantOrderRank(
|
||||
tenant("기술개발센터", "rnd-center"),
|
||||
),
|
||||
).toBe(Number.MAX_SAFE_INTEGER);
|
||||
});
|
||||
});
|
||||
65
orgfront/src/features/orgchart/hanmacFamilyOrder.ts
Normal file
65
orgfront/src/features/orgchart/hanmacFamilyOrder.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
export type HanmacFamilyOrderTenant = {
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
|
||||
export const HANMAC_FAMILY_ROOT_SLUG = "hanmac-family";
|
||||
|
||||
export const HANMAC_FAMILY_TENANT_ORDER = [
|
||||
"gpdtdc",
|
||||
"saman",
|
||||
"hanmac",
|
||||
"baron-group",
|
||||
] as const;
|
||||
|
||||
function normalizedTenantText(tenant: HanmacFamilyOrderTenant) {
|
||||
return `${tenant.slug} ${tenant.name}`.trim().toLowerCase();
|
||||
}
|
||||
|
||||
export function isHanmacFamilyRootTenant(tenant: HanmacFamilyOrderTenant) {
|
||||
return (
|
||||
tenant.slug.toLowerCase() === HANMAC_FAMILY_ROOT_SLUG ||
|
||||
tenant.name.includes("한맥가족")
|
||||
);
|
||||
}
|
||||
|
||||
export function getHanmacFamilyTenantOrderRank(
|
||||
tenant: HanmacFamilyOrderTenant,
|
||||
) {
|
||||
const text = normalizedTenantText(tenant);
|
||||
if (text.includes("gpdtdc") || text.includes("총괄기획")) return 0;
|
||||
if (text.includes("saman") || text.includes("삼안")) return 1;
|
||||
if (
|
||||
(text.includes("hanmac") || text.includes("한맥기술")) &&
|
||||
!isHanmacFamilyRootTenant(tenant)
|
||||
) {
|
||||
return 2;
|
||||
}
|
||||
if (text.includes("baron-group") || text.includes("바론그룹")) return 3;
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
export function compareHanmacFamilyTenants<T extends HanmacFamilyOrderTenant>(
|
||||
a: T,
|
||||
b: T,
|
||||
) {
|
||||
const rankDiff =
|
||||
getHanmacFamilyTenantOrderRank(a) - getHanmacFamilyTenantOrderRank(b);
|
||||
if (rankDiff !== 0) return rankDiff;
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
export function orderHanmacFamilyTenants<T extends HanmacFamilyOrderTenant>(
|
||||
tenants: readonly T[],
|
||||
) {
|
||||
return [...tenants].sort(compareHanmacFamilyTenants);
|
||||
}
|
||||
|
||||
export function orderHanmacFamilyChildren<T extends HanmacFamilyOrderTenant>(
|
||||
parent: HanmacFamilyOrderTenant,
|
||||
children: readonly T[],
|
||||
) {
|
||||
return isHanmacFamilyRootTenant(parent)
|
||||
? orderHanmacFamilyTenants(children)
|
||||
: [...children];
|
||||
}
|
||||
@@ -51,6 +51,40 @@ describe("buildOrgPickerTree", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("orders hanmac-family children by the shared organization policy", () => {
|
||||
const tenants = [
|
||||
tenant("hanmac-family-id", "COMPANY_GROUP", "한맥가족", "hanmac-family"),
|
||||
tenant(
|
||||
"baron-group-id",
|
||||
"COMPANY_GROUP",
|
||||
"바론그룹",
|
||||
"baron-group",
|
||||
"hanmac-family-id",
|
||||
),
|
||||
tenant("hanmac-id", "COMPANY", "한맥기술", "hanmac", "hanmac-family-id"),
|
||||
tenant("saman-id", "COMPANY", "삼안", "saman", "hanmac-family-id"),
|
||||
tenant(
|
||||
"gpdtdc-id",
|
||||
"ORGANIZATION",
|
||||
"총괄기획&기술개발센터",
|
||||
"gpdtdc",
|
||||
"hanmac-family-id",
|
||||
),
|
||||
];
|
||||
|
||||
const tree = buildOrgPickerTree({
|
||||
tenants,
|
||||
users: [] satisfies UserSummary[],
|
||||
});
|
||||
|
||||
expect(tree.roots[0]?.children.map((node) => node.name)).toEqual([
|
||||
"총괄기획&기술개발센터",
|
||||
"삼안",
|
||||
"한맥기술",
|
||||
"바론그룹",
|
||||
]);
|
||||
});
|
||||
|
||||
it("scopes descendant filtering by tenant slug", () => {
|
||||
const tenants = [
|
||||
tenant("hanmac-family-id", "COMPANY_GROUP", "한맥가족", "hanmac-family"),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { TenantSummary, UserSummary } from "../../lib/adminApi";
|
||||
import { type TenantNode, buildTenantFullTree } from "../../lib/tenantTree";
|
||||
import { orderHanmacFamilyChildren } from "./hanmacFamilyOrder";
|
||||
import type { OrgPickerTreeNode } from "./pickerTypes";
|
||||
import { filterTenantsByVisibility } from "./tenantVisibility";
|
||||
import { getOrgChartUserDisplayName } from "./userDisplay";
|
||||
@@ -50,9 +51,10 @@ function tenantToPickerNode(
|
||||
tenant: TenantNode,
|
||||
usersBySlug: Map<string, UserSummary[]>,
|
||||
): OrgPickerTreeNode {
|
||||
const tenantChildren = tenant.children.map((child) =>
|
||||
tenantToPickerNode(child, usersBySlug),
|
||||
);
|
||||
const tenantChildren = orderHanmacFamilyChildren(
|
||||
tenant,
|
||||
tenant.children,
|
||||
).map((child) => tenantToPickerNode(child, usersBySlug));
|
||||
const userChildren = (usersBySlug.get(tenant.slug.toLowerCase()) || []).map(
|
||||
(user) => ({
|
||||
type: "user" as const,
|
||||
@@ -150,9 +152,10 @@ export function buildOrgPickerTree({
|
||||
|
||||
if (!groupNode) return { roots: [], companies: [], companyGroupId: "" };
|
||||
|
||||
const companies = groupNode.children.filter(
|
||||
(node) => node.type === "COMPANY",
|
||||
);
|
||||
const companies = orderHanmacFamilyChildren(
|
||||
groupNode,
|
||||
groupNode.children,
|
||||
).filter((node) => node.type === "COMPANY");
|
||||
const scopedRoot = tenantId
|
||||
? findTenantNode([groupNode], tenantId)
|
||||
: groupNode;
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
fetchUsers,
|
||||
} from "../../../lib/adminApi";
|
||||
import { type TenantNode, buildTenantFullTree } from "../../../lib/tenantTree";
|
||||
import {
|
||||
orderHanmacFamilyChildren,
|
||||
orderHanmacFamilyTenants,
|
||||
} from "../hanmacFamilyOrder";
|
||||
import { filterTenantsByVisibility, getOrgUnitType } from "../tenantVisibility";
|
||||
import { getOrgChartUserDisplayName, getUserOrgProfile } from "../userDisplay";
|
||||
|
||||
@@ -565,7 +569,10 @@ function buildOrgNode(
|
||||
? 0
|
||||
: inheritedCompanyColorDepth + 1;
|
||||
const members = usersMap.get(slug) || [];
|
||||
const children = tenantNode.children.map((child) =>
|
||||
const children = orderHanmacFamilyChildren(
|
||||
tenantNode,
|
||||
tenantNode.children,
|
||||
).map((child) =>
|
||||
buildOrgNode(
|
||||
child,
|
||||
usersMap,
|
||||
@@ -1018,33 +1025,14 @@ function collectOrgSelectionDescendants(
|
||||
]);
|
||||
}
|
||||
|
||||
function getOrgSelectionPolicyRank(node: TenantNode) {
|
||||
const text = `${node.slug} ${node.name}`.toLowerCase();
|
||||
if (text.includes("gpdtdc") || text.includes("총괄기획")) return 1;
|
||||
if (text.includes("saman") || text.includes("삼안")) return 2;
|
||||
if (
|
||||
(text.includes("hanmac") || text.includes("한맥기술")) &&
|
||||
!text.includes("hanmac-family")
|
||||
) {
|
||||
return 3;
|
||||
}
|
||||
if (text.includes("baron") || text.includes("바론")) return 4;
|
||||
return 100;
|
||||
}
|
||||
|
||||
export function buildOrgSelectionOptions(
|
||||
familyRoot: TenantNode | null,
|
||||
): OrgSelectionOption[] {
|
||||
return (familyRoot?.children ?? [])
|
||||
.filter((node) =>
|
||||
return orderHanmacFamilyTenants(
|
||||
(familyRoot?.children ?? []).filter((node) =>
|
||||
["COMPANY_GROUP", "COMPANY", "ORGANIZATION"].includes(node.type),
|
||||
)
|
||||
.sort((a, b) => {
|
||||
const rankDiff =
|
||||
getOrgSelectionPolicyRank(a) - getOrgSelectionPolicyRank(b);
|
||||
if (rankDiff !== 0) return rankDiff;
|
||||
return a.name.localeCompare(b.name);
|
||||
})
|
||||
),
|
||||
)
|
||||
.map((node) => ({
|
||||
descendants: collectOrgSelectionDescendants(node, 2),
|
||||
id: node.id,
|
||||
|
||||
Reference in New Issue
Block a user