-
Notifications
You must be signed in to change notification settings - Fork 931
Show the primary user email on the Hosts page when multiple are present #48869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
spalmesano0
wants to merge
5
commits into
main
Choose a base branch
from
idp-username-in-column
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+232
−37
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
9d75fe5
Show the primary user email on the Hosts page when multiple are present
spalmesano0 1ce73c2
Add tests for the User email column on the Hosts page
spalmesano0 384890b
Add changelog
spalmesano0 f1d9f72
Fix stale tooltip visibility in TooltipTruncatedTextCell
spalmesano0 ada1dcd
Fix a test assertion that could never fail
spalmesano0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| - Hosts page's User email column now shows a host's IdP username (or first Chrome profile email if no IdP username) instead of a generic "N users" label, with a `+N` count and tooltip listing any additional emails. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
frontend/pages/hosts/ManageHostsPage/HostTableConfig.tests.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| import React from "react"; | ||
| import { render } from "@testing-library/react"; | ||
|
|
||
| import { | ||
| generateAvailableTableHeaders, | ||
| getPrimaryDeviceUser, | ||
| } from "./HostTableConfig"; | ||
|
|
||
| describe("getPrimaryDeviceUser", () => { | ||
| it("returns no primary email, no suffix, and no tooltip lines when there are no emails", () => { | ||
| expect(getPrimaryDeviceUser([])).toEqual({ | ||
| primaryEmail: undefined, | ||
| suffixCount: 0, | ||
| tooltipLines: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("returns the single email as primary with no suffix and no tooltip lines when there is exactly one", () => { | ||
| expect( | ||
| getPrimaryDeviceUser([{ email: "solo@acmecorp.com", source: "custom" }]) | ||
| ).toEqual({ | ||
| primaryEmail: "solo@acmecorp.com", | ||
| suffixCount: 0, | ||
| tooltipLines: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("prioritizes the IdP-sourced email over chrome/custom, regardless of array order", () => { | ||
| const { primaryEmail, suffixCount } = getPrimaryDeviceUser([ | ||
| { email: "custom1@acmecorp.com", source: "custom" }, | ||
| { email: "chrome@acmecorp.com", source: "google_chrome_profiles" }, | ||
| { email: "idp.user@acmecorp.com", source: "mdm_idp_accounts" }, | ||
| { email: "custom2@acmecorp.com", source: "custom" }, | ||
| ]); | ||
| expect(primaryEmail).toBe("idp.user@acmecorp.com"); | ||
| expect(suffixCount).toBe(3); | ||
| }); | ||
|
|
||
| it("falls back to the first chrome profile email when no IdP email is present", () => { | ||
| const { primaryEmail, suffixCount } = getPrimaryDeviceUser([ | ||
| { email: "custom1@acmecorp.com", source: "custom" }, | ||
| { email: "chrome@acmecorp.com", source: "google_chrome_profiles" }, | ||
| ]); | ||
| expect(primaryEmail).toBe("chrome@acmecorp.com"); | ||
| expect(suffixCount).toBe(1); | ||
| }); | ||
|
|
||
| it("falls back to the first available email when neither IdP nor chrome sources are present", () => { | ||
| const { primaryEmail, suffixCount } = getPrimaryDeviceUser([ | ||
| { email: "custom1@acmecorp.com", source: "custom" }, | ||
| { email: "custom2@acmecorp.com", source: "custom" }, | ||
| ]); | ||
| expect(primaryEmail).toBe("custom1@acmecorp.com"); | ||
| expect(suffixCount).toBe(1); | ||
| }); | ||
|
|
||
| it("lists the primary email first in tooltipLines, followed by the rest", () => { | ||
| const { tooltipLines } = getPrimaryDeviceUser([ | ||
| { email: "custom1@acmecorp.com", source: "custom" }, | ||
| { email: "idp.user@acmecorp.com", source: "mdm_idp_accounts" }, | ||
| ]); | ||
| expect(tooltipLines).toEqual([ | ||
| "idp.user@acmecorp.com", | ||
| "custom1@acmecorp.com", | ||
| ]); | ||
| }); | ||
|
|
||
| it("caps tooltipLines at 5 entries, appending a '+N more' line for the remainder", () => { | ||
| const users = Array.from({ length: 7 }, (_, i) => ({ | ||
| email: `user${i}@acmecorp.com`, | ||
| source: "custom", | ||
| })); | ||
| const { suffixCount, tooltipLines } = getPrimaryDeviceUser(users); | ||
| expect(suffixCount).toBe(6); | ||
| expect(tooltipLines).toEqual([ | ||
| "user0@acmecorp.com", | ||
| "user1@acmecorp.com", | ||
| "user2@acmecorp.com", | ||
| "user3@acmecorp.com", | ||
| "user4@acmecorp.com", | ||
| "+2 more", | ||
| ]); | ||
| }); | ||
|
|
||
| it("does not append a '+N more' line when the total is exactly the cap", () => { | ||
| const users = Array.from({ length: 5 }, (_, i) => ({ | ||
| email: `user${i}@acmecorp.com`, | ||
| source: "custom", | ||
| })); | ||
| const { tooltipLines } = getPrimaryDeviceUser(users); | ||
| expect(tooltipLines).toHaveLength(5); | ||
| expect(tooltipLines.some((line) => line.includes("more"))).toBe(false); | ||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| }); | ||
|
|
||
| describe("HostTableConfig - User email column", () => { | ||
| const getDeviceMappingColumn = () => { | ||
| const columns = generateAvailableTableHeaders({ | ||
| isFreeTier: false, | ||
| isOnlyObserver: false, | ||
| }); | ||
| const column = columns.find((c) => c.id === "device_mapping") as any; | ||
| if (!column) throw new Error("device_mapping column not found"); | ||
| return column; | ||
| }; | ||
|
|
||
| const renderCell = (value: Array<{ email: string; source: string }>) => { | ||
| const Cell = getDeviceMappingColumn().Cell as React.ElementType; | ||
| return render(<Cell cell={{ value }} />); | ||
| }; | ||
|
|
||
| it("renders the default empty value with no suffix when there are no emails", () => { | ||
| const { container } = renderCell([]); | ||
| const textEl = container.querySelector( | ||
| ".data-table__tooltip-truncated-text" | ||
| ); | ||
| expect(textEl?.textContent).toBe("---"); | ||
| expect( | ||
| container.querySelector(".data-table__suffix") | ||
| ).not.toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("renders the primary email with a '+N' suffix and enables the tooltip when there are multiple emails", () => { | ||
| const { container } = renderCell([ | ||
| { email: "custom1@acmecorp.com", source: "custom" }, | ||
| { email: "idp.user@acmecorp.com", source: "mdm_idp_accounts" }, | ||
| ]); | ||
| const textEl = container.querySelector( | ||
| ".data-table__tooltip-truncated-text" | ||
| ); | ||
| const suffixEl = container.querySelector(".data-table__suffix"); | ||
| const tooltipTrigger = container.querySelector( | ||
| ".data-table__tooltip-truncated-text-container" | ||
| ); | ||
|
|
||
| expect(textEl?.textContent).toBe("idp.user@acmecorp.com"); | ||
| expect(suffixEl?.textContent).toBe("+1"); | ||
| // Tooltip should be enabled here even though the primary email isn't | ||
| // long enough to be visually truncated, because a suffix is present. | ||
| expect(tooltipTrigger?.getAttribute("data-tip-disable")).toBe("false"); | ||
| }); | ||
|
|
||
| it("does not render a suffix or force the tooltip open for a single, untruncated email", () => { | ||
| const { container } = renderCell([ | ||
| { email: "solo@acmecorp.com", source: "custom" }, | ||
| ]); | ||
| expect( | ||
| container.querySelector(".data-table__suffix") | ||
| ).not.toBeInTheDocument(); | ||
| const tooltipTrigger = container.querySelector( | ||
| ".data-table__tooltip-truncated-text-container" | ||
| ); | ||
| expect(tooltipTrigger?.getAttribute("data-tip-disable")).toBe("true"); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.