From 9ec7d0d03e17e847e34c9149f65228c1302eb224 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Fri, 2 May 2025 13:37:39 -0700 Subject: [PATCH] Update login mapping rendering on ssh hosts --- .../SshHostsPage/components/SshHostsTable.tsx | 89 +++++++++++++------ 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx b/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx index 20d907038..9e36a4aac 100644 --- a/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx +++ b/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx @@ -91,34 +91,69 @@ export const SshHostsTable = ({ handlePopUpOpen }: Props) => { {host.loginMappings.length === 0 ? ( None ) : ( - Object.entries( - host.loginMappings.reduce( - (acc, mapping) => { - const key = `${mapping.loginUser}|${mapping.source}|${mapping.allowedPrincipals.usernames.sort().join(",")}`; - acc[key] = mapping; + (() => { + const hostMappings = host.loginMappings.filter( + (m) => m.source !== LoginMappingSource.HOST_GROUP + ); + const groupMappings = host.loginMappings.filter( + (m) => m.source === LoginMappingSource.HOST_GROUP + ); + + const hostLoginUserToPrincipals = hostMappings.reduce( + (acc, { loginUser, allowedPrincipals }) => { + acc[loginUser] = new Set(allowedPrincipals.usernames); return acc; }, - {} as Record - ) - ) - .sort(([a], [b]) => a.localeCompare(b)) - .map(([key, { loginUser, allowedPrincipals, source }]) => ( -
-
- {loginUser} - {source === LoginMappingSource.HOST_GROUP && ( - - (inherited from host group) - - )} -
- {allowedPrincipals.usernames.map((username) => ( -
- └─ {username} + {} as Record> + ); + + const entriesFromHost = hostMappings.map(({ loginUser, allowedPrincipals }) => ({ + loginUser, + source: LoginMappingSource.HOST, + usernames: allowedPrincipals.usernames + })); + + const entriesFromGroup = groupMappings + .map(({ loginUser, allowedPrincipals }) => { + const existing = hostLoginUserToPrincipals[loginUser] || new Set(); + const filteredUsernames = allowedPrincipals.usernames.filter((u) => !existing.has(u)); + return filteredUsernames.length > 0 + ? { + loginUser, + source: LoginMappingSource.HOST_GROUP, + usernames: filteredUsernames + } + : null; + }) + .filter(Boolean) as { + loginUser: string; + source: LoginMappingSource; + usernames: string[]; + }[]; + + return [...entriesFromHost, ...entriesFromGroup] + .sort((a, b) => a.loginUser.localeCompare(b.loginUser)) + .map(({ loginUser, usernames, source }) => ( +
+
+ {loginUser} + {source === LoginMappingSource.HOST_GROUP && ( + + (inherited from host group) + + )}
- ))} -
- )) + {usernames.map((username) => ( +
+ └─ {username} +
+ ))} +
+ )); + })() )} @@ -198,4 +233,8 @@ export const SshHostsTable = ({ handlePopUpOpen }: Props) => {
); +}; + + + ); };