refactor: Wrap forms into dashboard layout (#5697)

This commit is contained in:
Bruno Quaresma 2023-01-12 17:08:31 -03:00 committed by GitHub
parent bef6f67b70
commit 3861d1c555
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 170 additions and 266 deletions

View File

@ -18,7 +18,7 @@ import { Route, Routes } from "react-router-dom"
import { selectPermissions } from "xServices/auth/authSelectors"
import { selectFeatureVisibility } from "xServices/entitlements/entitlementsSelectors"
import { XServiceContext } from "xServices/StateContext"
import { NavbarLayout } from "./components/NavbarLayout/NavbarLayout"
import { DashboardLayout } from "./components/DashboardLayout/DashboardLayout"
import { RequireAuth } from "./components/RequireAuth/RequireAuth"
import { SettingsLayout } from "./components/SettingsLayout/SettingsLayout"
import { DeploySettingsLayout } from "components/DeploySettingsLayout/DeploySettingsLayout"
@ -134,132 +134,79 @@ export const AppRouter: FC = () => {
<Route path="login" element={<LoginPage />} />
<Route path="setup" element={<SetupPage />} />
{/* Authenticated routes */}
{/* Dashboard routes */}
<Route element={<RequireAuth />}>
<Route index element={<IndexPage />} />
<Route element={<DashboardLayout />}>
<Route index element={<IndexPage />} />
<Route path="cli-auth" element={<CliAuthenticationPage />} />
<Route path="gitauth" element={<GitAuthPage />} />
<Route path="cli-auth" element={<CliAuthenticationPage />} />
<Route path="gitauth" element={<GitAuthPage />} />
<Route
path="workspaces"
element={
<NavbarLayout>
<WorkspacesPage />
</NavbarLayout>
}
/>
<Route path="workspaces" element={<WorkspacesPage />} />
<Route path="starter-templates">
<Route
index
element={
<NavbarLayout>
<StarterTemplatesPage />
</NavbarLayout>
}
/>
<Route path="starter-templates">
<Route index element={<StarterTemplatesPage />} />
<Route path=":exampleId" element={<StarterTemplatePage />} />
</Route>
<Route
path=":exampleId"
element={
<NavbarLayout>
<StarterTemplatePage />
</NavbarLayout>
}
/>
</Route>
<Route path="templates">
<Route
index
element={
<NavbarLayout>
<TemplatesPage />
</NavbarLayout>
}
/>
<Route path="new" element={<CreateTemplatePage />} />
<Route path=":template">
<Route
index
element={
<NavbarLayout>
<Route path="templates">
<Route index element={<TemplatesPage />} />
<Route path="new" element={<CreateTemplatePage />} />
<Route path=":template">
<Route
index
element={
<TemplateLayout>
<TemplateSummaryPage />
</TemplateLayout>
</NavbarLayout>
}
/>
<Route
path="permissions"
element={
<NavbarLayout>
}
/>
<Route
path="permissions"
element={
<TemplateLayout>
<TemplatePermissionsPage />
</TemplateLayout>
</NavbarLayout>
}
/>
<Route path="workspace" element={<CreateWorkspacePage />} />
<Route path="settings" element={<TemplateSettingsPage />} />
<Route path="versions">
<Route
path=":version"
element={
<NavbarLayout>
<TemplateVersionPage />
</NavbarLayout>
}
/>
<Route path="workspace" element={<CreateWorkspacePage />} />
<Route path="settings" element={<TemplateSettingsPage />} />
<Route path="versions">
<Route path=":version" element={<TemplateVersionPage />} />
</Route>
</Route>
</Route>
</Route>
<Route path="users">
<Route
index
element={
<NavbarLayout>
<Route path="users">
<Route
index
element={
<UsersLayout>
<UsersPage />
</UsersLayout>
</NavbarLayout>
}
/>
<Route path="create" element={<CreateUserPage />} />
</Route>
}
/>
<Route path="create" element={<CreateUserPage />} />
</Route>
<Route path="/groups">
<Route
index
element={
<NavbarLayout>
<Route path="/groups">
<Route
index
element={
<UsersLayout>
<GroupsPage />
</UsersLayout>
</NavbarLayout>
}
/>
<Route path="create" element={<CreateGroupPage />} />
<Route
path=":groupId"
element={
<NavbarLayout>
<GroupPage />
</NavbarLayout>
}
/>
<Route path=":groupId/settings" element={<SettingsGroupPage />} />
</Route>
}
/>
<Route path="create" element={<CreateGroupPage />} />
<Route path=":groupId" element={<GroupPage />} />
<Route path=":groupId/settings" element={<SettingsGroupPage />} />
</Route>
<Route path="/audit">
<Route
index
element={
<NavbarLayout>
<Route path="/audit">
<Route
index
element={
<RequirePermission
isFeatureVisible={
featureVisibility[FeatureNames.AuditLog] &&
@ -268,16 +215,14 @@ export const AppRouter: FC = () => {
>
<AuditPage />
</RequirePermission>
</NavbarLayout>
}
/>
</Route>
}
/>
</Route>
<Route path="/settings/deployment">
<Route
path="general"
element={
<NavbarLayout>
<Route path="/settings/deployment">
<Route
path="general"
element={
<RequirePermission
isFeatureVisible={Boolean(
permissions?.viewDeploymentConfig,
@ -287,13 +232,11 @@ export const AppRouter: FC = () => {
<GeneralSettingsPage />
</DeploySettingsLayout>
</RequirePermission>
</NavbarLayout>
}
/>
<Route
path="security"
element={
<NavbarLayout>
}
/>
<Route
path="security"
element={
<RequirePermission
isFeatureVisible={Boolean(
permissions?.viewDeploymentConfig,
@ -303,13 +246,11 @@ export const AppRouter: FC = () => {
<SecuritySettingsPage />
</DeploySettingsLayout>
</RequirePermission>
</NavbarLayout>
}
/>
<Route
path="appearance"
element={
<NavbarLayout>
}
/>
<Route
path="appearance"
element={
<RequirePermission
isFeatureVisible={Boolean(
permissions?.viewDeploymentConfig,
@ -319,13 +260,11 @@ export const AppRouter: FC = () => {
<AppearanceSettingsPage />
</DeploySettingsLayout>
</RequirePermission>
</NavbarLayout>
}
/>
<Route
path="network"
element={
<NavbarLayout>
}
/>
<Route
path="network"
element={
<RequirePermission
isFeatureVisible={Boolean(
permissions?.viewDeploymentConfig,
@ -335,13 +274,11 @@ export const AppRouter: FC = () => {
<NetworkSettingsPage />
</DeploySettingsLayout>
</RequirePermission>
</NavbarLayout>
}
/>
<Route
path="userauth"
element={
<NavbarLayout>
}
/>
<Route
path="userauth"
element={
<RequirePermission
isFeatureVisible={Boolean(
permissions?.viewDeploymentConfig,
@ -351,13 +288,11 @@ export const AppRouter: FC = () => {
<UserAuthSettingsPage />
</DeploySettingsLayout>
</RequirePermission>
</NavbarLayout>
}
/>
<Route
path="gitauth"
element={
<NavbarLayout>
}
/>
<Route
path="gitauth"
element={
<RequirePermission
isFeatureVisible={Boolean(
permissions?.viewDeploymentConfig,
@ -367,72 +302,51 @@ export const AppRouter: FC = () => {
<GitAuthSettingsPage />
</DeploySettingsLayout>
</RequirePermission>
</NavbarLayout>
}
/>
</Route>
}
/>
</Route>
<Route path="settings">
<Route
path="account"
element={
<NavbarLayout>
<Route path="settings">
<Route
path="account"
element={
<SettingsLayout>
<AccountPage />
</SettingsLayout>
</NavbarLayout>
}
/>
<Route
path="security"
element={
<NavbarLayout>
}
/>
<Route
path="security"
element={
<SettingsLayout>
<SecurityPage />
</SettingsLayout>
</NavbarLayout>
}
/>
<Route
path="ssh-keys"
element={
<NavbarLayout>
}
/>
<Route
path="ssh-keys"
element={
<SettingsLayout>
<SSHKeysPage />
</SettingsLayout>
</NavbarLayout>
}
/>
</Route>
<Route path="/@:username">
<Route path=":workspace">
<Route
index
element={
<NavbarLayout>
<WorkspacePage />
</NavbarLayout>
}
/>
</Route>
<Route path="schedule" element={<WorkspaceSchedulePage />} />
<Route path="terminal" element={<TerminalPage />} />
<Route
path="builds/:buildNumber"
element={
<NavbarLayout>
<WorkspaceBuildPage />
</NavbarLayout>
}
/>
<Route
path="change-version"
element={<WorkspaceChangeVersionPage />}
/>
<Route path="/@:username">
<Route path=":workspace">
<Route index element={<WorkspacePage />} />
<Route path="schedule" element={<WorkspaceSchedulePage />} />
<Route path="terminal" element={<TerminalPage />} />
<Route
path="builds/:buildNumber"
element={<WorkspaceBuildPage />}
/>
<Route
path="change-version"
element={<WorkspaceChangeVersionPage />}
/>
</Route>
</Route>
</Route>
</Route>

View File

@ -62,7 +62,7 @@ export const CreateUserForm: FC<
)
return (
<FullPageForm title="Create user" onCancel={onCancel}>
<FullPageForm title="Create user">
<form onSubmit={form.handleSubmit} autoComplete="off">
<Stack spacing={1}>
<TextField

View File

@ -1,13 +1,14 @@
import { makeStyles } from "@material-ui/core/styles"
import { useActor } from "@xstate/react"
import { Loader } from "components/Loader/Loader"
import { FC, PropsWithChildren, Suspense, useContext, useEffect } from "react"
import { FC, Suspense, useContext, useEffect } from "react"
import { XServiceContext } from "../../xServices/StateContext"
import { Navbar } from "../Navbar/Navbar"
import { UpdateCheckBanner } from "components/UpdateCheckBanner/UpdateCheckBanner"
import { Margins } from "components/Margins/Margins"
import { Outlet } from "react-router-dom"
export const NavbarLayout: FC<PropsWithChildren> = ({ children }) => {
export const DashboardLayout: FC = () => {
const styles = useStyles()
const xServices = useContext(XServiceContext)
const [authState] = useActor(xServices.authXService)
@ -38,7 +39,9 @@ export const NavbarLayout: FC<PropsWithChildren> = ({ children }) => {
</div>
)}
<div className={styles.siteContent}>
<Suspense fallback={<Loader />}>{children}</Suspense>
<Suspense fallback={<Loader />}>
<Outlet />
</Suspense>
</div>
</div>
)

View File

@ -30,5 +30,4 @@ export const Example = Template.bind({})
Example.args = {
title: "My Form",
detail: "Lorem ipsum dolor",
onCancel: action("cancel"),
}

View File

@ -1,39 +1,38 @@
import { makeStyles } from "@material-ui/core/styles"
import { Margins } from "components/Margins/Margins"
import { FC, ReactNode } from "react"
import { FormCloseButton } from "../FormCloseButton/FormCloseButton"
import { FormTitle } from "../FormTitle/FormTitle"
import { Margins } from "../Margins/Margins"
import {
PageHeader,
PageHeaderTitle,
PageHeaderSubtitle,
} from "components/PageHeader/PageHeader"
import { makeStyles } from "@material-ui/core/styles"
export interface FullPageFormProps {
title: string
detail?: ReactNode
onCancel: () => void
}
const useStyles = makeStyles(() => ({
root: {
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
},
}))
export const FullPageForm: FC<React.PropsWithChildren<FullPageFormProps>> = ({
title,
detail,
onCancel,
children,
}) => {
const styles = useStyles()
return (
<main className={styles.root}>
<Margins size="small">
<FormTitle title={title} detail={detail} />
<FormCloseButton onClose={onCancel} />
{children}
</Margins>
</main>
return (
<Margins size="small">
<PageHeader className={styles.pageHeader}>
<PageHeaderTitle>{title}</PageHeaderTitle>
{detail && <PageHeaderSubtitle>{detail}</PageHeaderSubtitle>}
</PageHeader>
<main>{children}</main>
</Margins>
)
}
const useStyles = makeStyles((theme) => ({
pageHeader: {
paddingBottom: theme.spacing(2),
},
}))

View File

@ -1,13 +1,12 @@
import { FormCloseButton } from "../FormCloseButton/FormCloseButton"
import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
import { Margins } from "components/Margins/Margins"
import { FC, ReactNode } from "react"
export interface FormTitleProps {
title: string
detail?: ReactNode
}
import {
PageHeader,
PageHeaderTitle,
PageHeaderSubtitle,
} from "components/PageHeader/PageHeader"
import Button from "@material-ui/core/Button"
import { makeStyles } from "@material-ui/core/styles"
export interface FullPageHorizontalFormProps {
title: string
@ -21,35 +20,25 @@ export const FullPageHorizontalForm: FC<
const styles = useStyles()
return (
<>
<header className={styles.title}>
<Margins size="medium">
<Typography variant="h3">{title}</Typography>
{detail && <Typography variant="caption">{detail}</Typography>}
</Margins>
</header>
<Margins size="medium">
<PageHeader
actions={
<Button size="small" onClick={onCancel}>
Cancel
</Button>
}
>
<PageHeaderTitle>{title}</PageHeaderTitle>
{detail && <PageHeaderSubtitle>{detail}</PageHeaderSubtitle>}
</PageHeader>
<FormCloseButton onClose={onCancel} />
<main className={styles.main}>
<Margins size="medium">{children}</Margins>
</main>
</>
<main className={styles.form}>{children}</main>
</Margins>
)
}
const useStyles = makeStyles((theme) => ({
title: {
paddingTop: theme.spacing(6),
paddingBottom: theme.spacing(8),
[theme.breakpoints.down("sm")]: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
},
},
main: {
paddingBottom: theme.spacing(10),
form: {
marginTop: theme.spacing(1),
},
}))

View File

@ -280,7 +280,7 @@ export const WorkspaceScheduleForm: FC<
}
return (
<FullPageForm onCancel={onCancel} title={Language.formTitle}>
<FullPageForm title={Language.formTitle}>
<form onSubmit={form.handleSubmit} className={styles.form}>
<Stack>
{Boolean(submitScheduleError) && (

View File

@ -39,7 +39,7 @@ export const CreateGroupPageView: FC<CreateGroupPageViewProps> = ({
return (
<Margins>
<FullPageForm title="Create group" onCancel={onCancel}>
<FullPageForm title="Create group">
<form onSubmit={form.handleSubmit}>
<TextField
{...getFieldHelpers("name")}

View File

@ -54,7 +54,7 @@ const UpdateGroupForm: FC<{
const { t } = useTranslation("common")
return (
<FullPageForm title="Group settings" onCancel={onCancel}>
<FullPageForm title="Group settings">
<form onSubmit={form.handleSubmit}>
<TextField
{...getFieldHelpers("name")}

View File

@ -54,7 +54,7 @@ export const TemplateSettingsPageView: FC<TemplateSettingsPageViewProps> = ({
}
return (
<FullPageForm title={t("title")} onCancel={onCancel}>
<FullPageForm title={t("title")}>
{Boolean(errors.getTemplateError) && (
<Stack className={classes.errorContainer}>
<AlertBanner severity="error" error={errors.getTemplateError} />

View File

@ -21,7 +21,7 @@ export const WorkspaceChangeVersionPageView: FC<
const { workspace, templateVersions, template, error } = context
return (
<FullPageForm title="Change version" onCancel={() => navigate(-1)}>
<FullPageForm title="Change version">
<Stack>
<Maybe condition={Boolean(error)}>
<AlertBanner severity="error" error={error} />