forked from baron/baron-sso
userfront e2e 전체 테스트
This commit is contained in:
@@ -4,6 +4,8 @@ import {
|
||||
buildOrgSelectionOptions,
|
||||
buildUsersMap,
|
||||
clampScale,
|
||||
filterSystemGlobalTenants,
|
||||
getMemberGridMetrics,
|
||||
getOrgNodeHeaderFill,
|
||||
getSemanticZoomMode,
|
||||
layoutForest,
|
||||
@@ -83,8 +85,8 @@ describe("org chart layout", () => {
|
||||
expect(new Set(childNodes.map((node) => node.y)).size).toBe(1);
|
||||
});
|
||||
|
||||
it("uses member columns in node bounds when member count exceeds five", () => {
|
||||
const compactMembers = Array.from({ length: 6 }, (_, index) =>
|
||||
it("uses member columns in node bounds when the rendered node aspect ratio needs them", () => {
|
||||
const compactMembers = Array.from({ length: 10 }, (_, index) =>
|
||||
member(`member-${index + 1}`),
|
||||
);
|
||||
const node = {
|
||||
@@ -98,11 +100,11 @@ describe("org chart layout", () => {
|
||||
|
||||
expect(rootNode).toBeDefined();
|
||||
expect(rootNode?.width).toBeGreaterThan(340);
|
||||
expect(rootNode?.height).toBeLessThan(42 + 24 + 6 * 24);
|
||||
expect(rootNode?.height).toBeLessThan(42 + 24 + 10 * 24);
|
||||
expect(layout.width).toBeGreaterThan((rootNode?.width ?? 0) + 72 * 2 - 1);
|
||||
});
|
||||
|
||||
it("adds one member column per five-member quotient", () => {
|
||||
it("keeps modest member groups in one column until another column improves the rendered ratio", () => {
|
||||
const tenMembers = Array.from({ length: 10 }, (_, index) =>
|
||||
member(`member-${index + 1}`),
|
||||
);
|
||||
@@ -132,10 +134,15 @@ describe("org chart layout", () => {
|
||||
const sixNode = sixLayout.nodes.find((item) => item.node.id === "six");
|
||||
const tenNode = tenLayout.nodes.find((item) => item.node.id === "ten");
|
||||
|
||||
expect(sixNode?.width).toBeGreaterThan(340);
|
||||
expect(sixNode?.width).toBe(340);
|
||||
expect(tenNode?.width).toBeGreaterThan(sixNode?.width ?? 0);
|
||||
expect(tenNode?.height).toBeLessThan(42 + 24 + 10 * 24);
|
||||
expect(tenLayout.width).toBeGreaterThan(sixLayout.width);
|
||||
});
|
||||
|
||||
it("chooses member columns from the rendered node aspect ratio instead of fixed five-member buckets", () => {
|
||||
expect(getMemberGridMetrics(6)).toEqual({ columnCount: 1, rowCount: 6 });
|
||||
expect(getMemberGridMetrics(10)).toEqual({ columnCount: 2, rowCount: 5 });
|
||||
expect(getMemberGridMetrics(25)).toEqual({ columnCount: 2, rowCount: 13 });
|
||||
});
|
||||
|
||||
it("uses multi-column layout by default when sibling width crosses the threshold", () => {
|
||||
@@ -388,6 +395,40 @@ describe("org chart layout", () => {
|
||||
).toEqual(["총괄기획&기술개발센터", "삼안", "한맥기술", "바론그룹"]);
|
||||
});
|
||||
|
||||
it("always hides internal and private organizations from the organization status chart", () => {
|
||||
const visibleParent = tenantNode(
|
||||
"visible-parent",
|
||||
"COMPANY",
|
||||
"공개 회사",
|
||||
"visible-parent",
|
||||
);
|
||||
const internalOrg = {
|
||||
...tenantNode("internal-org", "ORGANIZATION", "내부 조직", "internal-org"),
|
||||
parentId: "visible-parent",
|
||||
config: { visibility: "internal" },
|
||||
};
|
||||
const internalChild = {
|
||||
...tenantNode("internal-child", "ORGANIZATION", "내부 하위", "internal-child"),
|
||||
parentId: "internal-org",
|
||||
};
|
||||
const privateOrg = {
|
||||
...tenantNode("private-org", "ORGANIZATION", "비공개 조직", "private-org"),
|
||||
parentId: "visible-parent",
|
||||
config: { visibility: "private" },
|
||||
};
|
||||
const publicOrg = {
|
||||
...tenantNode("public-org", "ORGANIZATION", "공개 조직", "public-org"),
|
||||
parentId: "visible-parent",
|
||||
};
|
||||
|
||||
expect(
|
||||
filterSystemGlobalTenants(
|
||||
[visibleParent, internalOrg, internalChild, privateOrg, publicOrg],
|
||||
"internal",
|
||||
).map((tenant) => tenant.id),
|
||||
).toEqual(["visible-parent", "public-org"]);
|
||||
});
|
||||
|
||||
it("maps legacy companyCode users to matching tenant slugs", () => {
|
||||
const usersMap = buildUsersMap(
|
||||
[
|
||||
|
||||
@@ -90,6 +90,8 @@ const MEMBER_COLUMN_GAP = 8;
|
||||
const HEADER_HEIGHT = 42;
|
||||
const MEMBER_ROW_HEIGHT = 24;
|
||||
const NODE_PADDING_Y = 12;
|
||||
const MEMBER_GRID_TARGET_ASPECT_RATIO = 2;
|
||||
const MAX_MEMBER_COLUMN_COUNT = 8;
|
||||
const ROOT_GAP_X = 120;
|
||||
const CHILD_GAP_Y = 96;
|
||||
const SIBLING_GAP_X = 80;
|
||||
@@ -155,15 +157,52 @@ function getRankWeight(
|
||||
return (isLeader ? -100 : 0) + (order === -1 ? 99 : order);
|
||||
}
|
||||
|
||||
export function getMemberGridMetrics(memberCount: number) {
|
||||
if (memberCount <= 0) return { columnCount: 1, rowCount: 1 };
|
||||
|
||||
const maxColumnCount = Math.min(
|
||||
MAX_MEMBER_COLUMN_COUNT,
|
||||
Math.max(1, memberCount),
|
||||
);
|
||||
let best = { columnCount: 1, rowCount: memberCount };
|
||||
let bestScore = Number.POSITIVE_INFINITY;
|
||||
|
||||
for (let columnCount = 1; columnCount <= maxColumnCount; columnCount += 1) {
|
||||
const rowCount = Math.ceil(memberCount / columnCount);
|
||||
const width =
|
||||
columnCount <= 1
|
||||
? NODE_WIDTH
|
||||
: Math.max(
|
||||
NODE_WIDTH,
|
||||
NODE_PADDING_Y * 2 +
|
||||
columnCount * MEMBER_COLUMN_WIDTH +
|
||||
(columnCount - 1) * MEMBER_COLUMN_GAP,
|
||||
);
|
||||
const height =
|
||||
HEADER_HEIGHT + NODE_PADDING_Y * 2 + rowCount * MEMBER_ROW_HEIGHT;
|
||||
const aspectRatio = width / height;
|
||||
const score = Math.abs(
|
||||
Math.log(aspectRatio / MEMBER_GRID_TARGET_ASPECT_RATIO),
|
||||
);
|
||||
|
||||
if (
|
||||
score < bestScore ||
|
||||
(score === bestScore && rowCount < best.rowCount)
|
||||
) {
|
||||
best = { columnCount, rowCount };
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
function getMemberColumnCount(memberCount: number) {
|
||||
return memberCount > 5 ? Math.floor(memberCount / 5) + 1 : 1;
|
||||
return getMemberGridMetrics(memberCount).columnCount;
|
||||
}
|
||||
|
||||
function getMemberRowCount(memberCount: number) {
|
||||
return Math.max(
|
||||
1,
|
||||
Math.ceil(memberCount / getMemberColumnCount(memberCount)),
|
||||
);
|
||||
return getMemberGridMetrics(memberCount).rowCount;
|
||||
}
|
||||
|
||||
function getNodeWidth(members: UserSummary[]) {
|
||||
@@ -1048,9 +1087,9 @@ function getOrgSelectionLabel(
|
||||
?.name;
|
||||
}
|
||||
|
||||
function filterSystemGlobalTenants(
|
||||
export function filterSystemGlobalTenants(
|
||||
tenants: TenantSummary[],
|
||||
visibilityMode: "internal" | "public" = "internal",
|
||||
_visibilityMode: "internal" | "public" = "public",
|
||||
) {
|
||||
const excludedIds = new Set(
|
||||
tenants.filter(isSystemGlobalTenant).map((tenant) => tenant.id),
|
||||
@@ -1074,7 +1113,7 @@ function filterSystemGlobalTenants(
|
||||
const filtered = tenants.filter(
|
||||
(tenant) => !excludedIds.has(tenant.id) && isOrgFrontTenantType(tenant),
|
||||
);
|
||||
return filterTenantsByVisibility(filtered, visibilityMode);
|
||||
return filterTenantsByVisibility(filtered, "public");
|
||||
}
|
||||
|
||||
type TenantIndexes = {
|
||||
|
||||
Reference in New Issue
Block a user