forked from baron/baron-sso
Fix org chart manager ordering and title wrapping
This commit is contained in:
@@ -104,6 +104,10 @@ const MEMBER_CARD_BASE_CHAR_COUNT = 8;
|
||||
const MEMBER_CARD_CHAR_WIDTH = 12;
|
||||
const MEMBER_CARD_TEXT_PADDING_X = 28;
|
||||
const MEMBER_COLUMN_MAX_WIDTH = 280;
|
||||
const NODE_HEADER_CHAR_WIDTH = 17;
|
||||
const NODE_HEADER_WRAP_THRESHOLD = 420;
|
||||
const NODE_HEADER_TEXT_PADDING_X = 112;
|
||||
const NODE_HEADER_TYPE_BADGE_WIDTH = 48;
|
||||
const MEMBER_GRID_TARGET_ASPECT_RATIO = 2;
|
||||
const MAX_MEMBER_COLUMN_COUNT = 8;
|
||||
const ROOT_GAP_X = 120;
|
||||
@@ -154,6 +158,24 @@ function getRankWeight(
|
||||
return getOrgRankWeight(profile.grade);
|
||||
}
|
||||
|
||||
function getManagerWeight(
|
||||
user: UserSummary,
|
||||
tenant?: { id: string; slug: string },
|
||||
) {
|
||||
return getUserOrgProfile(user, tenant).isManager ? 0 : 1;
|
||||
}
|
||||
|
||||
function compareOrgMembers(
|
||||
a: UserSummary,
|
||||
b: UserSummary,
|
||||
tenant?: { id: string; slug: string },
|
||||
) {
|
||||
return (
|
||||
getManagerWeight(a, tenant) - getManagerWeight(b, tenant) ||
|
||||
getRankWeight(a, tenant) - getRankWeight(b, tenant)
|
||||
);
|
||||
}
|
||||
|
||||
function getComplementaryColor(hexColor: string) {
|
||||
const normalized = hexColor.trim().replace("#", "");
|
||||
if (!/^[\da-f]{6}$/i.test(normalized)) return "#f59e0b";
|
||||
@@ -246,14 +268,37 @@ function getMemberRowCount(memberCount: number, memberColumnWidth?: number) {
|
||||
return getMemberGridMetrics(memberCount, memberColumnWidth).rowCount;
|
||||
}
|
||||
|
||||
function getNodeWidth(members: UserSummary[], memberColumnWidth: number) {
|
||||
function getNodeHeaderWidth(node: OrgNode) {
|
||||
const typeBadgeWidth = node.orgUnitType ? NODE_HEADER_TYPE_BADGE_WIDTH : 0;
|
||||
const titleTextWidth =
|
||||
getDisplayTextWidthUnit(node.name) * NODE_HEADER_CHAR_WIDTH;
|
||||
const oneLineWidth =
|
||||
NODE_HEADER_TEXT_PADDING_X + typeBadgeWidth + titleTextWidth;
|
||||
if (oneLineWidth <= NODE_HEADER_WRAP_THRESHOLD) {
|
||||
return Math.ceil(oneLineWidth);
|
||||
}
|
||||
const estimatedTitleWidth =
|
||||
NODE_HEADER_TEXT_PADDING_X + typeBadgeWidth + titleTextWidth / 2;
|
||||
return Math.ceil(estimatedTitleWidth);
|
||||
}
|
||||
|
||||
function getNodeWidth(
|
||||
node: OrgNode,
|
||||
members: UserSummary[],
|
||||
memberColumnWidth: number,
|
||||
) {
|
||||
const columnCount = getMemberColumnCount(members.length, memberColumnWidth);
|
||||
if (columnCount <= 1) {
|
||||
return Math.max(NODE_WIDTH, NODE_PADDING_Y * 2 + memberColumnWidth);
|
||||
return Math.max(
|
||||
NODE_WIDTH,
|
||||
getNodeHeaderWidth(node),
|
||||
NODE_PADDING_Y * 2 + memberColumnWidth,
|
||||
);
|
||||
}
|
||||
|
||||
return Math.max(
|
||||
NODE_WIDTH,
|
||||
getNodeHeaderWidth(node),
|
||||
NODE_PADDING_Y * 2 +
|
||||
columnCount * memberColumnWidth +
|
||||
(columnCount - 1) * MEMBER_COLUMN_GAP,
|
||||
@@ -775,9 +820,8 @@ function layoutTree(
|
||||
options: OrgChartLayoutOptions,
|
||||
): ChartLayout {
|
||||
const tenantIdentity = { id: node.id, slug: node.companyCode ?? "" };
|
||||
const members = [...node.members].sort(
|
||||
(a, b) =>
|
||||
getRankWeight(a, tenantIdentity) - getRankWeight(b, tenantIdentity),
|
||||
const members = [...node.members].sort((a, b) =>
|
||||
compareOrgMembers(a, b, tenantIdentity),
|
||||
);
|
||||
const memberColumnWidth = getMemberColumnWidth(members, tenantIdentity);
|
||||
const nodeHeight = getNodeHeight(members, memberColumnWidth);
|
||||
@@ -802,7 +846,7 @@ function layoutTree(
|
||||
const childCenters = childRoots.map(
|
||||
(childRoot) => childRoot.x + childRoot.width / 2,
|
||||
);
|
||||
const nodeWidth = getNodeWidth(members, memberColumnWidth);
|
||||
const nodeWidth = getNodeWidth(node, members, memberColumnWidth);
|
||||
const firstChildCenter =
|
||||
childCenters.length > 0 ? Math.min(...childCenters) : nodeWidth / 2;
|
||||
const lastChildCenter =
|
||||
@@ -2089,8 +2133,14 @@ function SvgOrgNode({
|
||||
const showCompactGlyph = !showNodeName;
|
||||
const titleClass =
|
||||
node.level <= 1
|
||||
? "text-[17px] font-black leading-tight"
|
||||
: "text-[14px] font-extrabold leading-tight";
|
||||
? "text-[17px] font-black leading-[1.05]"
|
||||
: "text-[14px] font-extrabold leading-[1.05]";
|
||||
const titleStyle: React.CSSProperties = {
|
||||
display: "-webkit-box",
|
||||
overflow: "hidden",
|
||||
WebkitBoxOrient: "vertical",
|
||||
WebkitLineClamp: 2,
|
||||
};
|
||||
|
||||
return (
|
||||
<foreignObject
|
||||
@@ -2117,7 +2167,10 @@ function SvgOrgNode({
|
||||
{node.orgUnitType}
|
||||
</span>
|
||||
) : null}
|
||||
<div className={`${titleClass} min-w-0 truncate`}>
|
||||
<div
|
||||
className={`${titleClass} min-w-0 break-words`}
|
||||
style={titleStyle}
|
||||
>
|
||||
{node.name}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user