feat: make template pages responsive (#3232)

This commit is contained in:
Abhineet Jain
2022-07-26 16:31:58 -04:00
committed by GitHub
parent 991b4f7480
commit 6f93acd964
7 changed files with 193 additions and 182 deletions

View File

@ -1,16 +0,0 @@
import { makeStyles } from "@material-ui/core/styles"
import { FC } from "react"
export const TableContainer: FC = ({ children }) => {
const styles = useStyles()
return <div className={styles.wrapper}>{children}</div>
}
const useStyles = makeStyles((theme) => ({
wrapper: {
overflowX: "auto",
borderRadius: theme.shape.borderRadius,
border: `1px solid ${theme.palette.divider}`,
},
}))

View File

@ -2,6 +2,7 @@ import { makeStyles } from "@material-ui/core/styles"
import Table from "@material-ui/core/Table" import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody" import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell" import TableCell from "@material-ui/core/TableCell"
import TableContainer from "@material-ui/core/TableContainer"
import TableHead from "@material-ui/core/TableHead" import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow" import TableRow from "@material-ui/core/TableRow"
import { AvatarData } from "components/AvatarData/AvatarData" import { AvatarData } from "components/AvatarData/AvatarData"
@ -26,70 +27,72 @@ export const TemplateResourcesTable: FC<TemplateResourcesProps> = ({ resources }
const styles = useStyles() const styles = useStyles()
return ( return (
<Table className={styles.table}> <TableContainer className={styles.tableContainer}>
<TableHead> <Table>
<TableHeaderRow> <TableHead>
<TableCell> <TableHeaderRow>
<Stack direction="row" spacing={0.5} alignItems="center"> <TableCell>
{Language.resourceLabel} <Stack direction="row" spacing={0.5} alignItems="center">
<ResourcesHelpTooltip /> {Language.resourceLabel}
</Stack> <ResourcesHelpTooltip />
</TableCell> </Stack>
<TableCell className={styles.agentColumn}> </TableCell>
<Stack direction="row" spacing={0.5} alignItems="center"> <TableCell className={styles.agentColumn}>
{Language.agentLabel} <Stack direction="row" spacing={0.5} alignItems="center">
<AgentHelpTooltip /> {Language.agentLabel}
</Stack> <AgentHelpTooltip />
</TableCell> </Stack>
</TableHeaderRow> </TableCell>
</TableHead> </TableHeaderRow>
<TableBody> </TableHead>
{resources.map((resource) => { <TableBody>
// We need to initialize the agents to display the resource {resources.map((resource) => {
const agents = resource.agents ?? [null] // We need to initialize the agents to display the resource
return agents.map((agent, agentIndex) => { const agents = resource.agents ?? [null]
// If there is no agent, just display the resource name return agents.map((agent, agentIndex) => {
if (!agent) { // If there is no agent, just display the resource name
if (!agent) {
return (
<TableRow>
<TableCell className={styles.resourceNameCell}>
<AvatarData
title={resource.name}
subtitle={resource.type}
highlightTitle
avatar={<ResourceAvatar type={resource.type} />}
/>
</TableCell>
<TableCell colSpan={3}></TableCell>
</TableRow>
)
}
return ( return (
<TableRow> <TableRow key={`${resource.id}-${agent.id}`}>
<TableCell className={styles.resourceNameCell}> {/* We only want to display the name in the first row because we are using rowSpan */}
<AvatarData {/* The rowspan should be the same than the number of agents */}
title={resource.name} {agentIndex === 0 && (
subtitle={resource.type} <TableCell className={styles.resourceNameCell} rowSpan={agents.length}>
highlightTitle <AvatarData
avatar={<ResourceAvatar type={resource.type} />} title={resource.name}
/> subtitle={resource.type}
highlightTitle
avatar={<ResourceAvatar type={resource.type} />}
/>
</TableCell>
)}
<TableCell className={styles.agentColumn}>
{agent.name}
<span className={styles.operatingSystem}>{agent.operating_system}</span>
</TableCell> </TableCell>
<TableCell colSpan={3}></TableCell>
</TableRow> </TableRow>
) )
} })
})}
return ( </TableBody>
<TableRow key={`${resource.id}-${agent.id}`}> </Table>
{/* We only want to display the name in the first row because we are using rowSpan */} </TableContainer>
{/* The rowspan should be the same than the number of agents */}
{agentIndex === 0 && (
<TableCell className={styles.resourceNameCell} rowSpan={agents.length}>
<AvatarData
title={resource.name}
subtitle={resource.type}
highlightTitle
avatar={<ResourceAvatar type={resource.type} />}
/>
</TableCell>
)}
<TableCell className={styles.agentColumn}>
{agent.name}
<span className={styles.operatingSystem}>{agent.operating_system}</span>
</TableCell>
</TableRow>
)
})
})}
</TableBody>
</Table>
) )
} }
@ -98,7 +101,7 @@ const useStyles = makeStyles((theme) => ({
margin: 0, margin: 0,
}, },
table: { tableContainer: {
border: 0, border: 0,
}, },

View File

@ -1,9 +1,9 @@
import Table from "@material-ui/core/Table" import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody" import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell" import TableCell from "@material-ui/core/TableCell"
import TableContainer from "@material-ui/core/TableContainer"
import TableHead from "@material-ui/core/TableHead" import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow" import TableRow from "@material-ui/core/TableRow"
import { TableContainer } from "components/TableContainer/TableContainer"
import { FC } from "react" import { FC } from "react"
import * as TypesGen from "../../api/typesGenerated" import * as TypesGen from "../../api/typesGenerated"
import { UsersTableBody } from "./UsersTableBody" import { UsersTableBody } from "./UsersTableBody"

View File

@ -3,6 +3,7 @@ import { Theme } from "@material-ui/core/styles"
import Table from "@material-ui/core/Table" import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody" import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell" import TableCell from "@material-ui/core/TableCell"
import TableContainer from "@material-ui/core/TableContainer"
import TableHead from "@material-ui/core/TableHead" import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow" import TableRow from "@material-ui/core/TableRow"
import useTheme from "@material-ui/styles/useTheme" import useTheme from "@material-ui/styles/useTheme"
@ -27,48 +28,50 @@ export const VersionsTable: FC<VersionsTableProps> = ({ versions }) => {
const theme: Theme = useTheme() const theme: Theme = useTheme()
return ( return (
<Table data-testid="versions-table"> <TableContainer>
<TableHead> <Table data-testid="versions-table">
<TableRow> <TableHead>
<TableCell width="30%">{Language.nameLabel}</TableCell>
<TableCell width="30%">{Language.createdAtLabel}</TableCell>
<TableCell width="40%">{Language.createdByLabel}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{isLoading && <TableLoader />}
{versions &&
versions
.slice()
.reverse()
.map((version) => {
return (
<TableRow key={version.id} data-testid={`version-${version.id}`}>
<TableCell>{version.name}</TableCell>
<TableCell>
<span style={{ color: theme.palette.text.secondary }}>
{new Date(version.created_at).toLocaleString()}
</span>
</TableCell>
<TableCell>
<span style={{ color: theme.palette.text.secondary }}>
{version.created_by_name}
</span>
</TableCell>
</TableRow>
)
})}
{versions && versions.length === 0 && (
<TableRow> <TableRow>
<TableCell colSpan={999}> <TableCell width="30%">{Language.nameLabel}</TableCell>
<Box p={4}> <TableCell width="30%">{Language.createdAtLabel}</TableCell>
<EmptyState message={Language.emptyMessage} /> <TableCell width="40%">{Language.createdByLabel}</TableCell>
</Box>
</TableCell>
</TableRow> </TableRow>
)} </TableHead>
</TableBody> <TableBody>
</Table> {isLoading && <TableLoader />}
{versions &&
versions
.slice()
.reverse()
.map((version) => {
return (
<TableRow key={version.id} data-testid={`version-${version.id}`}>
<TableCell>{version.name}</TableCell>
<TableCell>
<span style={{ color: theme.palette.text.secondary }}>
{new Date(version.created_at).toLocaleString()}
</span>
</TableCell>
<TableCell>
<span style={{ color: theme.palette.text.secondary }}>
{version.created_by_name}
</span>
</TableCell>
</TableRow>
)
})}
{versions && versions.length === 0 && (
<TableRow>
<TableCell colSpan={999}>
<Box p={4}>
<EmptyState message={Language.emptyMessage} />
</Box>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
) )
} }

View File

@ -26,6 +26,14 @@ AllStates.args = {
], ],
} }
export const SmallViewport = Template.bind({})
SmallViewport.args = {
...AllStates.args,
}
SmallViewport.parameters = {
chromatic: { viewports: [600] },
}
export const EmptyCanCreate = Template.bind({}) export const EmptyCanCreate = Template.bind({})
EmptyCanCreate.args = { EmptyCanCreate.args = {
canCreateTemplate: true, canCreateTemplate: true,

View File

@ -3,6 +3,7 @@ import { fade, makeStyles } from "@material-ui/core/styles"
import Table from "@material-ui/core/Table" import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody" import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell" import TableCell from "@material-ui/core/TableCell"
import TableContainer from "@material-ui/core/TableContainer"
import TableHead from "@material-ui/core/TableHead" import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow" import TableRow from "@material-ui/core/TableRow"
import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight" import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"
@ -94,73 +95,77 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = (props) => {
)} )}
</PageHeader> </PageHeader>
<Table> <TableContainer>
<TableHead> <Table>
<TableRow> <TableHead>
<TableCell>{Language.nameLabel}</TableCell>
<TableCell>{Language.usedByLabel}</TableCell>
<TableCell>{Language.lastUpdatedLabel}</TableCell>
<TableCell>{Language.createdByLabel}</TableCell>
<TableCell width="1%"></TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.loading && <TableLoader />}
{!props.loading && !props.templates?.length && (
<TableRow> <TableRow>
<TableCell colSpan={999}> <TableCell>{Language.nameLabel}</TableCell>
<EmptyState <TableCell>{Language.usedByLabel}</TableCell>
message={Language.emptyMessage} <TableCell>{Language.lastUpdatedLabel}</TableCell>
description={ <TableCell>{Language.createdByLabel}</TableCell>
props.canCreateTemplate ? Language.emptyDescription : Language.emptyViewNoPerms <TableCell width="1%"></TableCell>
}
descriptionClassName={styles.emptyDescription}
cta={<CodeExample code="coder template init" />}
/>
</TableCell>
</TableRow> </TableRow>
)} </TableHead>
{props.templates?.map((template) => { <TableBody>
const templatePageLink = `/templates/${template.name}` {props.loading && <TableLoader />}
return ( {!props.loading && !props.templates?.length && (
<TableRow <TableRow>
key={template.id} <TableCell colSpan={999}>
hover <EmptyState
data-testid={`template-${template.id}`} message={Language.emptyMessage}
tabIndex={0} description={
onKeyDown={(event) => { props.canCreateTemplate
if (event.key === "Enter") { ? Language.emptyDescription
navigate(templatePageLink) : Language.emptyViewNoPerms
} }
}} descriptionClassName={styles.emptyDescription}
className={styles.clickableTableRow} cta={<CodeExample code="coder template init" />}
>
<TableCellLink to={templatePageLink}>
<AvatarData
title={template.name}
subtitle={template.description}
highlightTitle
/> />
</TableCellLink> </TableCell>
<TableCellLink to={templatePageLink}>
{Language.developerCount(template.workspace_owner_count)}
</TableCellLink>
<TableCellLink data-chromatic="ignore" to={templatePageLink}>
{createDayString(template.updated_at)}
</TableCellLink>
<TableCellLink to={templatePageLink}>{template.created_by_name}</TableCellLink>
<TableCellLink to={templatePageLink}>
<div className={styles.arrowCell}>
<KeyboardArrowRight className={styles.arrowRight} />
</div>
</TableCellLink>
</TableRow> </TableRow>
) )}
})} {props.templates?.map((template) => {
</TableBody> const templatePageLink = `/templates/${template.name}`
</Table> return (
<TableRow
key={template.id}
hover
data-testid={`template-${template.id}`}
tabIndex={0}
onKeyDown={(event) => {
if (event.key === "Enter") {
navigate(templatePageLink)
}
}}
className={styles.clickableTableRow}
>
<TableCellLink to={templatePageLink}>
<AvatarData
title={template.name}
subtitle={template.description}
highlightTitle
/>
</TableCellLink>
<TableCellLink to={templatePageLink}>
{Language.developerCount(template.workspace_owner_count)}
</TableCellLink>
<TableCellLink data-chromatic="ignore" to={templatePageLink}>
{createDayString(template.updated_at)}
</TableCellLink>
<TableCellLink to={templatePageLink}>{template.created_by_name}</TableCellLink>
<TableCellLink to={templatePageLink}>
<div className={styles.arrowCell}>
<KeyboardArrowRight className={styles.arrowRight} />
</div>
</TableCellLink>
</TableRow>
)
})}
</TableBody>
</Table>
</TableContainer>
</Margins> </Margins>
) )
} }

View File

@ -17,6 +17,14 @@ Admin.args = {
canEditUsers: true, canEditUsers: true,
} }
export const SmallViewport = Template.bind({})
SmallViewport.args = {
...Admin.args,
}
SmallViewport.parameters = {
chromatic: { viewports: [600] },
}
export const Member = Template.bind({}) export const Member = Template.bind({})
Member.args = { ...Admin.args, canCreateUser: false, canEditUsers: false } Member.args = { ...Admin.args, canCreateUser: false, canEditUsers: false }