Skip to content

Commit c1d612f

Browse files
committed
feat: Add user menu on users table
1 parent 365c96c commit c1d612f

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed

site/src/components/Table/Table.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,21 @@ export interface TableProps<T> {
4040
* Optional empty state UI when the data is empty
4141
*/
4242
emptyState?: React.ReactElement
43+
/**
44+
* Optional element to render row actions like delete, update, etc
45+
*/
46+
rowMenu?: (data: T) => React.ReactElement
4347
}
4448

45-
export const Table = <T,>({ columns, data, emptyState, title }: TableProps<T>): React.ReactElement => {
49+
export const Table = <T,>({ columns, data, emptyState, title, rowMenu }: TableProps<T>): React.ReactElement => {
4650
const columnNames = columns.map(({ name }) => name)
47-
const body = renderTableBody(data, columns, emptyState)
51+
const body = renderTableBody(data, columns, emptyState, rowMenu)
4852

4953
return (
5054
<MuiTable>
5155
<TableHead>
5256
{title && <TableTitle title={title} />}
53-
<TableHeaders columns={columnNames} />
57+
<TableHeaders columns={columnNames} hasMenu={!!rowMenu} />
5458
</TableHead>
5559
{body}
5660
</MuiTable>
@@ -60,7 +64,12 @@ export const Table = <T,>({ columns, data, emptyState, title }: TableProps<T>):
6064
/**
6165
* Helper function to render the table data, falling back to an empty state if available
6266
*/
63-
const renderTableBody = <T,>(data: T[], columns: Column<T>[], emptyState?: React.ReactElement) => {
67+
const renderTableBody = <T,>(
68+
data: T[],
69+
columns: Column<T>[],
70+
emptyState?: React.ReactElement,
71+
rowMenu?: (data: T) => React.ReactElement,
72+
) => {
6473
if (data.length > 0) {
6574
const rows = data.map((item: T, index) => {
6675
const cells = columns.map((column) => {
@@ -70,7 +79,12 @@ const renderTableBody = <T,>(data: T[], columns: Column<T>[], emptyState?: React
7079
return <TableCell key={String(column.key)}>{String(item[column.key]).toString()}</TableCell>
7180
}
7281
})
73-
return <TableRow key={index}>{cells}</TableRow>
82+
return (
83+
<TableRow key={index}>
84+
{cells}
85+
{rowMenu && <TableCell>{rowMenu(item)}</TableCell>}
86+
</TableRow>
87+
)
7488
})
7589
return <TableBody>{rows}</TableBody>
7690
} else {

site/src/components/TableHeaders/TableHeaders.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import React from "react"
55

66
export interface TableHeadersProps {
77
columns: string[]
8+
hasMenu?: boolean
89
}
910

10-
export const TableHeaders: React.FC<TableHeadersProps> = ({ columns }) => {
11+
export const TableHeaders: React.FC<TableHeadersProps> = ({ columns, hasMenu }) => {
1112
const styles = useStyles()
1213
return (
1314
<TableRow className={styles.root}>
@@ -16,6 +17,8 @@ export const TableHeaders: React.FC<TableHeadersProps> = ({ columns }) => {
1617
{c}
1718
</TableCell>
1819
))}
20+
{/* 1% is a hack to make the table cell width fits the content */}
21+
{hasMenu && <TableCell width="1%" />}
1922
</TableRow>
2023
)
2124
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import IconButton from "@material-ui/core/IconButton"
2+
import Menu, { MenuProps } from "@material-ui/core/Menu"
3+
import MenuItem from "@material-ui/core/MenuItem"
4+
import MoreVertIcon from "@material-ui/icons/MoreVert"
5+
import React from "react"
6+
import { UserResponse } from "../../api/types"
7+
8+
export const UserMenu: React.FC<{ user: UserResponse }> = () => {
9+
const [anchorEl, setAnchorEl] = React.useState<MenuProps["anchorEl"]>(null)
10+
11+
const handleClick = (event: React.MouseEvent) => {
12+
setAnchorEl(event.currentTarget)
13+
}
14+
15+
const handleClose = () => {
16+
setAnchorEl(null)
17+
}
18+
19+
return (
20+
<>
21+
<IconButton size="small" aria-label="more" aria-controls="long-menu" aria-haspopup="true" onClick={handleClick}>
22+
<MoreVertIcon />
23+
</IconButton>
24+
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
25+
<MenuItem onClick={handleClose}>Suspend</MenuItem>
26+
</Menu>
27+
</>
28+
)
29+
}

site/src/components/UsersTable/UsersTable.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { UserResponse } from "../../api/types"
33
import { EmptyState } from "../EmptyState/EmptyState"
44
import { Column, Table } from "../Table/Table"
55
import { UserCell } from "../UserCell/UserCell"
6+
import { UserMenu } from "./UserMenu"
67

78
const Language = {
89
pageTitle: "Users",
@@ -28,5 +29,13 @@ export interface UsersTableProps {
2829
}
2930

3031
export const UsersTable: React.FC<UsersTableProps> = ({ users }) => {
31-
return <Table columns={columns} data={users} title={Language.usersTitle} emptyState={emptyState} />
32+
return (
33+
<Table
34+
columns={columns}
35+
data={users}
36+
title={Language.usersTitle}
37+
emptyState={emptyState}
38+
rowMenu={(user) => <UserMenu user={user} />}
39+
/>
40+
)
3241
}

0 commit comments

Comments
 (0)