Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7a6df41

Browse files
committed
feat(site): add UserCell component
Summary: This is a first step in porting over v1 AuditLog in a refactored/cleaned up fashion. This isn't a direct port, since we do not yet have a UserAvatar component. Details: - Port over UserCell from v1, sans UserAvatar impl - Add tests and stories for UserCell Notes: We do not have a holistic solution for handling localization, but starting from some kind of easy way that collects/resources strings will make the migration significantly easier. It will also help out our product copy owner, @khorne3 with maintenance. An RFC regarding this might be necessitated. Impact: This change does not have any user-facing impact yet, because the UserCell is not yet rendered in the product. This enables an incremental approach to migrating in the FE of the Audit Log, which is still waiting on the BE port. Relations: - This commit relates to #472, but does not finish it. - This commit should not merge until after #465 and #483 because it's based on them.
1 parent 22f820c commit 7a6df41

File tree

5 files changed

+173
-5
lines changed

5 files changed

+173
-5
lines changed

site/src/api/types.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
export interface LoginResponse {
2-
session_token: string
3-
}
4-
51
export interface UserResponse {
62
readonly id: string
73
readonly username: string
@@ -59,3 +55,10 @@ export interface Workspace {
5955
export interface APIKeyResponse {
6056
key: string
6157
}
58+
59+
export interface UserAgent {
60+
readonly ip_address: string
61+
readonly os: string
62+
readonly browser: string
63+
readonly device: string
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ComponentMeta, Story } from "@storybook/react"
2+
import React from "react"
3+
import { MockUser, MockUserAgent } from "../../test_helpers"
4+
import { UserCell, UserCellProps } from "./UserCell"
5+
6+
export default {
7+
title: "AuditLog/Cells/UserCell",
8+
component: UserCell,
9+
argTypes: {
10+
onSelectEmail: {
11+
action: "onSelectEmail",
12+
},
13+
},
14+
} as ComponentMeta<typeof UserCell>
15+
16+
const Template: Story<UserCellProps> = (args) => <UserCell {...args} />
17+
18+
export const Example = Template.bind({})
19+
Example.args = {
20+
user: MockUser,
21+
userAgent: MockUserAgent,
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { MockUser, MockUserAgent, WrapperComponent } from "../../test_helpers"
2+
import { LANGUAGE, UserCell, UserCellProps } from "./UserCell"
3+
import React from "react"
4+
import { fireEvent, render, screen } from "@testing-library/react"
5+
6+
namespace Helpers {
7+
export const Props: UserCellProps = {
8+
onSelectEmail: jest.fn(),
9+
user: MockUser,
10+
userAgent: MockUserAgent,
11+
}
12+
13+
export const Component: React.FC<UserCellProps> = (props) => (
14+
<WrapperComponent>
15+
<UserCell {...props} />
16+
</WrapperComponent>
17+
)
18+
}
19+
20+
describe("UserCell", () => {
21+
// callbacks
22+
it("calls onUserClick when an email address is clicked", () => {
23+
// Given
24+
const onSelectEmailMock = jest.fn()
25+
const props: UserCellProps = {
26+
...Helpers.Props,
27+
onSelectEmail: onSelectEmailMock,
28+
}
29+
30+
// When - click the user's email address
31+
render(<Helpers.Component {...props} />)
32+
fireEvent.click(screen.getByText(props.user.email))
33+
34+
// Then - callback was fired once
35+
expect(onSelectEmailMock).toHaveBeenCalledTimes(1)
36+
})
37+
38+
// email address cases
39+
it("renders an existing members' email address", () => {
40+
// Given
41+
const props: UserCellProps = Helpers.Props
42+
43+
// When
44+
render(<Helpers.Component {...props} />)
45+
46+
// Then - email address is visible
47+
expect(screen.getByText(props.user.email)).toBeDefined()
48+
})
49+
it(`renders '${LANGUAGE.emptyUser}' for non-existing members`, () => {
50+
// Given
51+
const props: UserCellProps = {
52+
...Helpers.Props,
53+
user: {
54+
...MockUser,
55+
email: "",
56+
},
57+
}
58+
59+
// When
60+
render(<Helpers.Component {...props} />)
61+
62+
// Then - 'Deleted user' is visible
63+
expect(screen.getByText(LANGUAGE.emptyUser)).toBeDefined()
64+
})
65+
66+
// ip address
67+
it("renders user agent IP address", () => {
68+
// Given
69+
const props: UserCellProps = Helpers.Props
70+
71+
// When
72+
render(<Helpers.Component {...props} />)
73+
74+
// Then - ip address is visible
75+
expect(screen.getByText(props.userAgent.ip_address)).toBeDefined()
76+
})
77+
})
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import Box from "@material-ui/core/Box"
2+
import Link from "@material-ui/core/Link"
3+
import { makeStyles } from "@material-ui/core/styles"
4+
import Typography from "@material-ui/core/Typography"
5+
import React from "react"
6+
import { UserAgent, UserResponse } from "../../api/types"
7+
8+
export const LANGUAGE = {
9+
emptyUser: "Deleted user",
10+
}
11+
12+
export interface UserCellProps {
13+
onSelectEmail: () => void
14+
user: UserResponse
15+
userAgent: UserAgent
16+
}
17+
18+
const useStyles = makeStyles((theme) => ({
19+
primaryText: {
20+
color: theme.palette.text.primary,
21+
fontSize: "16px",
22+
lineHeight: "15px",
23+
marginBottom: "5px",
24+
25+
"&.MuiTypography-caption": {
26+
cursor: "pointer",
27+
},
28+
},
29+
}))
30+
31+
export const UserCell: React.FC<UserCellProps> = ({ onSelectEmail, user, userAgent }) => {
32+
const styles = useStyles()
33+
34+
return (
35+
<Box alignItems="center" display="flex" flexDirection="row">
36+
{/* TODO - adjust margin */}
37+
{/* <Box display="flex" margin="auto 14px auto 0"> */}
38+
{/* TODO - implement UserAvatar */}
39+
{/* <UserAvatar user={user} popover /> */}
40+
{/* </Box> */}
41+
42+
<Box display="flex" flexDirection="column">
43+
{user.email ? (
44+
<Link className={styles.primaryText} onClick={onSelectEmail} variant="caption">
45+
{user.email}
46+
</Link>
47+
) : (
48+
<Typography color="textSecondary" variant="caption">
49+
{LANGUAGE.emptyUser}
50+
</Typography>
51+
)}
52+
53+
<Typography color="textSecondary" variant="caption">
54+
{userAgent.ip_address}
55+
</Typography>
56+
</Box>
57+
</Box>
58+
)
59+
}

site/src/test_helpers/entities.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Provisioner, Organization, Project, Workspace, UserResponse } from "../api/types"
1+
import { Provisioner, Organization, Project, Workspace, UserResponse, UserAgent } from "../api/types"
22

33
export const MockSessionToken = { session_token: "my-session-token" }
44

@@ -41,3 +41,10 @@ export const MockWorkspace: Workspace = {
4141
project_id: "project-id",
4242
owner_id: "test-user-id",
4343
}
44+
45+
export const MockUserAgent: UserAgent = {
46+
browser: "Chrome 99.0.4844",
47+
device: "Other",
48+
ip_address: "11.22.33.44",
49+
os: "Windows 10",
50+
}

0 commit comments

Comments
 (0)