feat: Add selected template link at the template select field (#1918)

This commit is contained in:
Bruno Quaresma
2022-05-31 13:28:22 -05:00
committed by GitHub
parent 75bcb739f9
commit 65c17a04df
10 changed files with 164 additions and 122 deletions

View File

@ -7,6 +7,7 @@ import * as TypesGen from "../../api/typesGenerated"
import { getFormHelpers, nameValidator, onChangeTrimmed } from "../../util/formUtils" import { getFormHelpers, nameValidator, onChangeTrimmed } from "../../util/formUtils"
import { FormFooter } from "../FormFooter/FormFooter" import { FormFooter } from "../FormFooter/FormFooter"
import { FullPageForm } from "../FullPageForm/FullPageForm" import { FullPageForm } from "../FullPageForm/FullPageForm"
import { Stack } from "../Stack/Stack"
export const Language = { export const Language = {
emailLabel: "Email", emailLabel: "Email",
@ -57,6 +58,7 @@ export const CreateUserForm: FC<CreateUserFormProps> = ({
return ( return (
<FullPageForm title="Create user" onCancel={onCancel}> <FullPageForm title="Create user" onCancel={onCancel}>
<form onSubmit={form.handleSubmit}> <form onSubmit={form.handleSubmit}>
<Stack spacing={1}>
<TextField <TextField
{...getFieldHelpers("username")} {...getFieldHelpers("username")}
onChange={onChangeTrimmed(form)} onChange={onChangeTrimmed(form)}
@ -83,6 +85,7 @@ export const CreateUserForm: FC<CreateUserFormProps> = ({
type="password" type="password"
variant="outlined" variant="outlined"
/> />
</Stack>
{error && <FormHelperText error>{error}</FormHelperText>} {error && <FormHelperText error>{error}</FormHelperText>}
<FormFooter onCancel={onCancel} isLoading={isLoading} /> <FormFooter onCancel={onCancel} isLoading={isLoading} />
</form> </form>

View File

@ -14,16 +14,17 @@ export interface FormFooterProps {
submitLabel?: string submitLabel?: string
} }
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme) => ({
footer: { footer: {
display: "flex", display: "flex",
flex: "0", flex: "0",
flexDirection: "row", flexDirection: "row",
justifyContent: "center", gap: theme.spacing(1.5),
alignItems: "center", alignItems: "center",
marginTop: theme.spacing(3),
}, },
button: { button: {
margin: "1em", width: "100%",
}, },
})) }))

View File

@ -9,9 +9,8 @@ export interface FormTitleProps {
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
title: { title: {
textAlign: "center", marginTop: theme.spacing(6),
marginTop: theme.spacing(5), marginBottom: theme.spacing(4),
marginBottom: theme.spacing(5),
"& h3": { "& h3": {
marginBottom: theme.spacing(1), marginBottom: theme.spacing(1),

View File

@ -23,7 +23,7 @@ export const FullPageForm: FC<FullPageFormProps> = ({ title, detail, onCancel, c
const styles = useStyles() const styles = useStyles()
return ( return (
<main className={styles.root}> <main className={styles.root}>
<Margins> <Margins size="small">
<FormTitle title={title} detail={detail} /> <FormTitle title={title} detail={detail} />
<FormCloseButton onClose={onCancel} /> <FormCloseButton onClose={onCancel} />

View File

@ -1,18 +1,30 @@
import { makeStyles } from "@material-ui/core/styles" import { makeStyles } from "@material-ui/core/styles"
import { FC } from "react" import { FC } from "react"
import { maxWidth, sidePadding } from "../../theme/constants" import { containerWidth, sidePadding } from "../../theme/constants"
type Size = "regular" | "medium" | "small"
const widthBySize: Record<Size, number> = {
regular: containerWidth,
medium: containerWidth / 2,
small: containerWidth / 3,
}
const useStyles = makeStyles(() => ({ const useStyles = makeStyles(() => ({
margins: { margins: {
margin: "0 auto", margin: "0 auto",
maxWidth, maxWidth: ({ maxWidth }: { maxWidth: number }) => maxWidth,
padding: `0 ${sidePadding}`, padding: `0 ${sidePadding}px`,
flex: 1, flex: 1,
width: "100%", width: "100%",
}, },
})) }))
export const Margins: FC = ({ children }) => { interface MarginsProps {
const styles = useStyles() size?: Size
}
export const Margins: FC<MarginsProps> = ({ children, size = "regular" }) => {
const styles = useStyles({ maxWidth: widthBySize[size] })
return <div className={styles.margins}>{children}</div> return <div className={styles.margins}>{children}</div>
} }

View File

@ -1,8 +1,7 @@
import FormControlLabel from "@material-ui/core/FormControlLabel" import FormControlLabel from "@material-ui/core/FormControlLabel"
import Paper from "@material-ui/core/Paper"
import Radio from "@material-ui/core/Radio" import Radio from "@material-ui/core/Radio"
import RadioGroup from "@material-ui/core/RadioGroup" import RadioGroup from "@material-ui/core/RadioGroup"
import { lighten, makeStyles } from "@material-ui/core/styles" import { makeStyles } from "@material-ui/core/styles"
import TextField from "@material-ui/core/TextField" import TextField from "@material-ui/core/TextField"
import { FC } from "react" import { FC } from "react"
import { ParameterSchema } from "../../api/typesGenerated" import { ParameterSchema } from "../../api/typesGenerated"
@ -17,7 +16,7 @@ export interface ParameterInputProps {
export const ParameterInput: FC<ParameterInputProps> = ({ disabled, onChange, schema }) => { export const ParameterInput: FC<ParameterInputProps> = ({ disabled, onChange, schema }) => {
const styles = useStyles() const styles = useStyles()
return ( return (
<Paper className={styles.paper}> <div className={styles.root}>
<div className={styles.title}> <div className={styles.title}>
<h2>var.{schema.name}</h2> <h2>var.{schema.name}</h2>
{schema.description && <span>{schema.description}</span>} {schema.description && <span>{schema.description}</span>}
@ -25,7 +24,7 @@ export const ParameterInput: FC<ParameterInputProps> = ({ disabled, onChange, sc
<div className={styles.input}> <div className={styles.input}>
<ParameterField disabled={disabled} onChange={onChange} schema={schema} /> <ParameterField disabled={disabled} onChange={onChange} schema={schema} />
</div> </div>
</Paper> </div>
) )
} }
@ -67,28 +66,26 @@ const ParameterField: React.FC<ParameterInputProps> = ({ disabled, onChange, sch
} }
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
paper: { root: {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
fontFamily: MONOSPACE_FONT_FAMILY, fontFamily: MONOSPACE_FONT_FAMILY,
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(2),
}, },
title: { title: {
background: lighten(theme.palette.background.default, 0.1),
borderBottom: `1px solid ${theme.palette.divider}`,
padding: theme.spacing(3),
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
"& h2": { "& h2": {
margin: 0, margin: 0,
}, },
"& span": { "& span": {
paddingTop: theme.spacing(2), paddingTop: theme.spacing(1),
}, },
}, },
input: { input: {
padding: theme.spacing(3), marginTop: theme.spacing(2),
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
maxWidth: 480,
}, },
})) }))

View File

@ -167,8 +167,8 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
return ( return (
<FullPageForm onCancel={onCancel} title="Workspace Schedule"> <FullPageForm onCancel={onCancel} title="Workspace Schedule">
<form className={styles.form} onSubmit={form.handleSubmit}> <form onSubmit={form.handleSubmit} className={styles.form}>
<Stack className={styles.stack}> <Stack>
<TextField <TextField
{...formHelpers("startTime", Language.startTimeHelperText)} {...formHelpers("startTime", Language.startTimeHelperText)}
disabled={form.isSubmitting || isLoading} disabled={form.isSubmitting || isLoading}
@ -177,7 +177,6 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
}} }}
label={Language.startTimeLabel} label={Language.startTimeLabel}
type="time" type="time"
variant="standard"
/> />
<TextField <TextField
@ -195,7 +194,6 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
shrink: true, shrink: true,
}} }}
label={Language.timezoneLabel} label={Language.timezoneLabel}
variant="standard"
/> />
<FormControl component="fieldset" error={Boolean(form.errors.monday)}> <FormControl component="fieldset" error={Boolean(form.errors.monday)}>
@ -212,6 +210,9 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
disabled={!form.values.startTime || form.isSubmitting || isLoading} disabled={!form.values.startTime || form.isSubmitting || isLoading}
onChange={form.handleChange} onChange={form.handleChange}
name={checkbox.name} name={checkbox.name}
color="primary"
size="small"
disableRipple
/> />
} }
key={checkbox.name} key={checkbox.name}
@ -229,7 +230,6 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
inputProps={{ min: 0, step: 1 }} inputProps={{ min: 0, step: 1 }}
label={Language.ttlLabel} label={Language.ttlLabel}
type="number" type="number"
variant="standard"
/> />
<FormFooter onCancel={onCancel} isLoading={form.isSubmitting || isLoading} /> <FormFooter onCancel={onCancel} isLoading={form.isSubmitting || isLoading} />
@ -241,21 +241,10 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
const useStyles = makeStyles({ const useStyles = makeStyles({
form: { form: {
display: "flex",
justifyContent: "center",
"& input": { "& input": {
colorScheme: "dark", colorScheme: "dark",
}, },
}, },
stack: {
// REMARK: 360 is 'arbitrary' in that it gives the helper text enough room
// to render on one line. If we change the text, we might want to
// adjust these. Without constraining the width, the date picker
// and number inputs aren't visually appealing or maximally usable.
maxWidth: 360,
minWidth: 360,
},
daysOfWeekLabel: { daysOfWeekLabel: {
fontSize: 12, fontSize: 12,
}, },

View File

@ -1,13 +1,16 @@
import Link from "@material-ui/core/Link"
import MenuItem from "@material-ui/core/MenuItem" import MenuItem from "@material-ui/core/MenuItem"
import { makeStyles } from "@material-ui/core/styles"
import TextField, { TextFieldProps } from "@material-ui/core/TextField" import TextField, { TextFieldProps } from "@material-ui/core/TextField"
import OpenInNewIcon from "@material-ui/icons/OpenInNew"
import { FormikContextType, useFormik } from "formik" import { FormikContextType, useFormik } from "formik"
import { FC, useState } from "react" import { FC, useState } from "react"
import { Link as RouterLink } from "react-router-dom"
import * as Yup from "yup" import * as Yup from "yup"
import * as TypesGen from "../../api/typesGenerated" import * as TypesGen from "../../api/typesGenerated"
import { FormFooter } from "../../components/FormFooter/FormFooter" import { FormFooter } from "../../components/FormFooter/FormFooter"
import { FullPageForm } from "../../components/FullPageForm/FullPageForm" import { FullPageForm } from "../../components/FullPageForm/FullPageForm"
import { Loader } from "../../components/Loader/Loader" import { Loader } from "../../components/Loader/Loader"
import { Margins } from "../../components/Margins/Margins"
import { ParameterInput } from "../../components/ParameterInput/ParameterInput" import { ParameterInput } from "../../components/ParameterInput/ParameterInput"
import { Stack } from "../../components/Stack/Stack" import { Stack } from "../../components/Stack/Stack"
import { getFormHelpers, nameValidator, onChangeTrimmed } from "../../util/formUtils" import { getFormHelpers, nameValidator, onChangeTrimmed } from "../../util/formUtils"
@ -35,6 +38,7 @@ export const validationSchema = Yup.object({
export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props) => { export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props) => {
const [parameterValues, setParameterValues] = useState<Record<string, string>>({}) const [parameterValues, setParameterValues] = useState<Record<string, string>>({})
const styles = useStyles()
const form: FormikContextType<TypesGen.CreateWorkspaceRequest> = useFormik<TypesGen.CreateWorkspaceRequest>({ const form: FormikContextType<TypesGen.CreateWorkspaceRequest> = useFormik<TypesGen.CreateWorkspaceRequest>({
initialValues: { initialValues: {
name: "", name: "",
@ -67,6 +71,10 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props)
}, },
}) })
const getFieldHelpers = getFormHelpers<TypesGen.CreateWorkspaceRequest>(form) const getFieldHelpers = getFormHelpers<TypesGen.CreateWorkspaceRequest>(form)
const selectedTemplate =
props.templates &&
form.values.template_id &&
props.templates.find((template) => template.id === form.values.template_id)
const handleTemplateChange: TextFieldProps["onChange"] = (event) => { const handleTemplateChange: TextFieldProps["onChange"] = (event) => {
if (!props.templates) { if (!props.templates) {
@ -85,7 +93,6 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props)
} }
return ( return (
<Margins>
<FullPageForm title="Create workspace" onCancel={props.onCancel}> <FullPageForm title="Create workspace" onCancel={props.onCancel}>
<form onSubmit={form.handleSubmit}> <form onSubmit={form.handleSubmit}>
{props.loadingTemplates && <Loader />} {props.loadingTemplates && <Loader />}
@ -101,6 +108,18 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props)
label={Language.templateLabel} label={Language.templateLabel}
variant="outlined" variant="outlined"
select select
helperText={
selectedTemplate && (
<Link
className={styles.readMoreLink}
component={RouterLink}
to={`/templates/${selectedTemplate.name}`}
target="_blank"
>
Read more about this template <OpenInNewIcon />
</Link>
)
}
> >
{props.templates.map((template) => ( {props.templates.map((template) => (
<MenuItem key={template.id} value={template.id}> <MenuItem key={template.id} value={template.id}>
@ -146,6 +165,18 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props)
</Stack> </Stack>
</form> </form>
</FullPageForm> </FullPageForm>
</Margins>
) )
} }
const useStyles = makeStyles((theme) => ({
readMoreLink: {
display: "flex",
alignItems: "center",
"& svg": {
width: 12,
height: 12,
marginLeft: theme.spacing(0.5),
},
},
}))

View File

@ -7,8 +7,8 @@ export const BODY_FONT_FAMILY = `"Inter", sans-serif`
export const lightButtonShadow = "0 2px 2px rgba(0, 23, 121, 0.08)" export const lightButtonShadow = "0 2px 2px rgba(0, 23, 121, 0.08)"
export const emptyBoxShadow = "none" export const emptyBoxShadow = "none"
export const navHeight = 62 export const navHeight = 62
export const maxWidth = 1380 export const containerWidth = 1380
export const sidePadding = "50px" export const sidePadding = 24
export const TitleIconSize = 48 export const TitleIconSize = 48
export const CardRadius = 2 export const CardRadius = 2
export const CardPadding = 20 export const CardPadding = 20

View File

@ -95,5 +95,15 @@ export const getOverrides = (palette: PaletteOptions) => {
border: `1px solid ${palette.divider}`, border: `1px solid ${palette.divider}`,
}, },
}, },
MuiFormHelperText: {
contained: {
marginLeft: 0,
marginRight: 0,
},
marginDense: {
marginTop: 8,
},
},
} }
} }