mirror of https://github.com/coder/coder.git
refactor: Wrap forms into dashboard layout (#5697)
This commit is contained in:
parent
bef6f67b70
commit
3861d1c555
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
)
|
|
@ -30,5 +30,4 @@ export const Example = Template.bind({})
|
|||
Example.args = {
|
||||
title: "My Form",
|
||||
detail: "Lorem ipsum dolor",
|
||||
onCancel: action("cancel"),
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
}))
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
}))
|
||||
|
|
|
@ -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) && (
|
||||
|
|
|
@ -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")}
|
||||
|
|
|
@ -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")}
|
||||
|
|
|
@ -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} />
|
||||
|
|
|
@ -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} />
|
||||
|
|
Loading…
Reference in New Issue