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

Skip to content

refactor: Improve the load state for the list pages #1428

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

Merged
merged 10 commits into from
May 13, 2022
6 changes: 3 additions & 3 deletions site/src/components/EmptyState/EmptyState.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ describe("EmptyState", () => {
await screen.findByText("Friendly greeting")
})

it("renders description component", async () => {
it("renders cta component", async () => {
// Given
const description = <button title="Click me" />
const cta = <button title="Click me" />

// When
render(<EmptyState message="Hello, world" description={description} />)
render(<EmptyState message="Hello, world" cta={cta} />)

// Then
await screen.findByText("Hello, world")
Expand Down
41 changes: 18 additions & 23 deletions site/src/components/EmptyState/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Box from "@material-ui/core/Box"
import Button, { ButtonProps } from "@material-ui/core/Button"
import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
import React from "react"
Expand All @@ -8,8 +7,8 @@ export interface EmptyStateProps {
/** Text Message to display, placed inside Typography component */
message: string
/** Longer optional description to display below the message */
description?: React.ReactNode
button?: ButtonProps
description?: string
cta?: React.ReactNode
}

/**
Expand All @@ -21,17 +20,22 @@ export interface EmptyStateProps {
* that you can directly pass props through to to customize the shape and layout of it.
*/
export const EmptyState: React.FC<EmptyStateProps> = (props) => {
const { message, description, button, ...boxProps } = props
const { message, description, cta, ...boxProps } = props
const styles = useStyles()
const buttonClassName = `${styles.button} ${button && button.className ? button.className : ""}`

return (
<Box className={styles.root} {...boxProps}>
<Typography variant="h5" color="textSecondary" className={styles.header}>
{message}
</Typography>
{description && <div className={styles.description}>{description}</div>}
{button && <Button variant="contained" color="primary" {...button} className={buttonClassName} />}
<div className={styles.header}>
<Typography variant="h5" className={styles.title}>
{message}
</Typography>
{description && (
<Typography variant="body2" color="textSecondary" className={styles.description}>
{description}
</Typography>
)}
</div>
{cta}
</Box>
)
}
Expand All @@ -48,22 +52,13 @@ const useStyles = makeStyles(
padding: theme.spacing(3),
},
header: {
marginBottom: theme.spacing(3),
},
title: {
fontWeight: 400,
},
description: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(1),
color: theme.palette.text.secondary,
fontSize: theme.typography.body2.fontSize,
},
button: {
marginTop: theme.spacing(2),
},
icon: {
fontSize: theme.typography.h2.fontSize,
color: theme.palette.text.secondary,
marginBottom: theme.spacing(1),
opacity: 0.5,
marginTop: theme.spacing(1),
},
}),
{ name: "EmptyState" },
Expand Down
3 changes: 2 additions & 1 deletion site/src/components/Loader/FullScreenLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import CircularProgress from "@material-ui/core/CircularProgress"
import { makeStyles } from "@material-ui/core/styles"
import React from "react"

export const useStyles = makeStyles(() => ({
export const useStyles = makeStyles((theme) => ({
root: {
position: "absolute",
top: "0",
Expand All @@ -12,6 +12,7 @@ export const useStyles = makeStyles(() => ({
display: "flex",
justifyContent: "center",
alignItems: "center",
background: theme.palette.background.default,
},
}))

Expand Down
23 changes: 3 additions & 20 deletions site/src/components/NavbarView/NavbarView.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Story } from "@storybook/react"
import React from "react"
import { MockUser, MockUser2 } from "../../testHelpers/entities"
import { NavbarView, NavbarViewProps } from "./NavbarView"

export default {
Expand All @@ -14,33 +15,15 @@ const Template: Story<NavbarViewProps> = (args: NavbarViewProps) => <NavbarView

export const ForAdmin = Template.bind({})
ForAdmin.args = {
user: {
id: "1",
username: "Administrator",
email: "[email protected]",
created_at: "dawn",
status: "active",
organization_ids: [],
roles: [],
},
displayAdminDropdown: true,
user: MockUser,
onSignOut: () => {
return Promise.resolve()
},
}

export const ForMember = Template.bind({})
ForMember.args = {
user: {
id: "1",
username: "CathyCoder",
email: "[email protected]",
created_at: "dawn",
status: "active",
organization_ids: [],
roles: [],
},
displayAdminDropdown: false,
user: MockUser2,
onSignOut: () => {
return Promise.resolve()
},
Expand Down
27 changes: 27 additions & 0 deletions site/src/components/TableLoader/TableLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Box from "@material-ui/core/Box"
import CircularProgress from "@material-ui/core/CircularProgress"
import { makeStyles } from "@material-ui/core/styles"
import TableCell from "@material-ui/core/TableCell"
import TableRow from "@material-ui/core/TableRow"
import React from "react"

export const TableLoader: React.FC = () => {
const styles = useStyles()

return (
<TableRow>
<TableCell colSpan={999} className={styles.cell}>
<Box p={4}>
<CircularProgress size={26} />
</Box>
</TableCell>
</TableRow>
)
}

const useStyles = makeStyles((theme) => ({
cell: {
textAlign: "center",
height: theme.spacing(20),
},
}))
29 changes: 29 additions & 0 deletions site/src/components/TemplatesTable/TemplatesTable.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ComponentMeta, Story } from "@storybook/react"
import React from "react"
import { MockOrganization, MockTemplate } from "../../testHelpers/entities"
import { TemplatesTable, TemplatesTableProps } from "./TemplatesTable"

export default {
title: "components/TemplatesTable",
component: TemplatesTable,
} as ComponentMeta<typeof TemplatesTable>

const Template: Story<TemplatesTableProps> = (args) => <TemplatesTable {...args} />

export const Example = Template.bind({})
Example.args = {
templates: [MockTemplate],
organizations: [MockOrganization],
}

export const Empty = Template.bind({})
Empty.args = {
templates: [],
organizations: [],
}

export const Loading = Template.bind({})
Loading.args = {
templates: undefined,
organizations: [],
}
81 changes: 81 additions & 0 deletions site/src/components/TemplatesTable/TemplatesTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import Box from "@material-ui/core/Box"
import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell"
import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow"
import React from "react"
import { Link } from "react-router-dom"
import * as TypesGen from "../../api/typesGenerated"
import { CodeExample } from "../../components/CodeExample/CodeExample"
import { EmptyState } from "../../components/EmptyState/EmptyState"
import { TableHeaderRow } from "../../components/TableHeaders/TableHeaders"
import { TableLoader } from "../../components/TableLoader/TableLoader"
import { TableTitle } from "../../components/TableTitle/TableTitle"

export const Language = {
title: "Templates",
tableTitle: "All templates",
nameLabel: "Name",
emptyMessage: "No templates have been created yet",
emptyDescription: "Run the following command to get started:",
totalLabel: "total",
}

export interface TemplatesTableProps {
templates?: TypesGen.Template[]
organizations?: TypesGen.Organization[]
}

export const TemplatesTable: React.FC<TemplatesTableProps> = ({ templates, organizations }) => {
const isLoading = !templates || !organizations

// Create a dictionary of organization ID -> organization Name
// Needed to properly construct links to dive into a template
const orgDictionary =
organizations &&
organizations.reduce((acc: Record<string, string>, curr: TypesGen.Organization) => {
return {
...acc,
[curr.id]: curr.name,
}
}, {})

return (
<Table>
<TableHead>
<TableTitle title={Language.tableTitle} />
<TableHeaderRow>
<TableCell size="small">{Language.nameLabel}</TableCell>
</TableHeaderRow>
</TableHead>
<TableBody>
{isLoading && <TableLoader />}
{templates &&
organizations &&
orgDictionary &&
templates.map((t) => (
<TableRow key={t.id}>
<TableCell>
<Link to={`/templates/${orgDictionary[t.organization_id]}/${t.name}`}>{t.name}</Link>
</TableCell>
</TableRow>
))}

{templates && templates.length === 0 && (
<TableRow>
<TableCell colSpan={999}>
<Box p={4}>
<EmptyState
message={Language.emptyMessage}
description={Language.emptyDescription}
cta={<CodeExample code="coder templates create" />}
/>
</Box>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
)
}
74 changes: 40 additions & 34 deletions site/src/components/UsersTable/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as TypesGen from "../../api/typesGenerated"
import { EmptyState } from "../EmptyState/EmptyState"
import { RoleSelect } from "../RoleSelect/RoleSelect"
import { TableHeaderRow } from "../TableHeaders/TableHeaders"
import { TableLoader } from "../TableLoader/TableLoader"
import { TableRowMenu } from "../TableRowMenu/TableRowMenu"
import { TableTitle } from "../TableTitle/TableTitle"
import { UserCell } from "../UserCell/UserCell"
Expand All @@ -24,12 +25,12 @@ export const Language = {
}

export interface UsersTableProps {
users: TypesGen.User[]
users?: TypesGen.User[]
roles?: TypesGen.Role[]
isUpdatingUserRoles?: boolean
onSuspendUser: (user: TypesGen.User) => void
onResetUserPassword: (user: TypesGen.User) => void
onUpdateUserRoles: (user: TypesGen.User, roles: TypesGen.Role["name"][]) => void
roles: TypesGen.Role[]
isUpdatingUserRoles?: boolean
}

export const UsersTable: React.FC<UsersTableProps> = ({
Expand All @@ -40,6 +41,8 @@ export const UsersTable: React.FC<UsersTableProps> = ({
onUpdateUserRoles,
isUpdatingUserRoles,
}) => {
const isLoading = !users || !roles

return (
<Table>
<TableHead>
Expand All @@ -52,38 +55,41 @@ export const UsersTable: React.FC<UsersTableProps> = ({
</TableHeaderRow>
</TableHead>
<TableBody>
{users.map((u) => (
<TableRow key={u.id}>
<TableCell>
<UserCell Avatar={{ username: u.username }} primaryText={u.username} caption={u.email} />{" "}
</TableCell>
<TableCell>
<RoleSelect
roles={roles}
selectedRoles={u.roles}
loading={isUpdatingUserRoles}
onChange={(roles) => onUpdateUserRoles(u, roles)}
/>
</TableCell>
<TableCell>
<TableRowMenu
data={u}
menuItems={[
{
label: Language.suspendMenuItem,
onClick: onSuspendUser,
},
{
label: Language.resetPasswordMenuItem,
onClick: onResetUserPassword,
},
]}
/>
</TableCell>
</TableRow>
))}
{isLoading && <TableLoader />}
{users &&
roles &&
users.map((u) => (
<TableRow key={u.id}>
<TableCell>
<UserCell Avatar={{ username: u.username }} primaryText={u.username} caption={u.email} />{" "}
</TableCell>
<TableCell>
<RoleSelect
roles={roles}
selectedRoles={u.roles}
loading={isUpdatingUserRoles}
onChange={(roles) => onUpdateUserRoles(u, roles)}
/>
</TableCell>
<TableCell>
<TableRowMenu
data={u}
menuItems={[
{
label: Language.suspendMenuItem,
onClick: onSuspendUser,
},
{
label: Language.resetPasswordMenuItem,
onClick: onResetUserPassword,
},
]}
/>
</TableCell>
</TableRow>
))}

{users.length === 0 && (
{users && users.length === 0 && (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe next time we're in here, we can break this file apart a bit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing.

<TableRow>
<TableCell colSpan={999}>
<Box p={4}>
Expand Down
Loading