Skip to content

Commit

Permalink
frontend: Add workflow layout component (#3143)
Browse files Browse the repository at this point in the history
  • Loading branch information
septum authored Oct 18, 2024
1 parent 51a09f9 commit 3d39574
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 10 deletions.
41 changes: 31 additions & 10 deletions frontend/packages/core/src/AppProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Landing from "../landing";
import type { ClutchError } from "../Network/errors";
import NotFound from "../not-found";
import type { AppConfiguration } from "../Types";
import WorkflowLayout, { LayoutProps } from "../WorkflowLayout";

import { registeredWorkflows } from "./registrar";
import ShortLinkProxy, { ShortLinkBaseRoute } from "./short-link-proxy";
Expand Down Expand Up @@ -214,21 +215,41 @@ const ClutchApp = ({
const heading = route.displayName
? `${workflow.displayName}: ${route.displayName}`
: workflow.displayName;

// We define these props in order to avoid UI changes before refactoring
const workflowLayoutProps: LayoutProps = {
variant: "custom",
hideHeader: true,
heading,
...route.layoutProps,
};

const workflowRouteComponent = (
<AppNotification
type="layout"
workflow={workflow?.displayName}
banners={appConfiguration?.banners}
>
{React.cloneElement(<route.component />, {
...route.componentProps,
// This is going to be removed to be used in the WorkflowLayout only
heading,
})}
</AppNotification>
);

return (
<Route
key={workflow.path}
path={`${route.path.replace(/^\/+/, "").replace(/\/+$/, "")}`}
element={
<AppNotification
type="layout"
workflow={workflow?.displayName}
banners={appConfiguration?.banners}
>
{React.cloneElement(<route.component />, {
...route.componentProps,
heading,
})}
</AppNotification>
appConfiguration?.enableWorkflowLayout ? (
<WorkflowLayout {...workflowLayoutProps}>
{workflowRouteComponent}
</WorkflowLayout>
) : (
workflowRouteComponent
)
}
/>
);
Expand Down
3 changes: 3 additions & 0 deletions frontend/packages/core/src/AppProvider/workflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Alert, Grid, IconButton } from "@mui/material";

import { Dialog, DialogContent } from "../dialog";
import Code from "../text";
import type { LayoutProps } from "../WorkflowLayout";

import type { WorkflowIcon } from "./index";

Expand Down Expand Up @@ -90,6 +91,8 @@ export interface Route {
* If this is not set the route will always be registered.
*/
featureFlag?: string;

layoutProps?: LayoutProps;
}

export interface ConfiguredRoute extends Route {
Expand Down
1 change: 1 addition & 0 deletions frontend/packages/core/src/Types/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export interface AppConfiguration {
/** Supports a react node or a string representing a public assets path */
logo?: React.ReactNode | string;
banners?: AppBanners;
enableWorkflowLayout?: boolean;
}
89 changes: 89 additions & 0 deletions frontend/packages/core/src/WorkflowLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React from "react";
import type { Interpolation } from "@emotion/styled";
import type { CSSObject, Theme } from "@mui/material";

import styled from "../styled";
import { Typography } from "../typography";

export type LayoutVariant = "standard" | "wizard" | "custom";

export type LayoutProps = {
variant: LayoutVariant;
heading?: string | React.ReactElement;
hideHeader?: boolean;
};

type StyledVariantComponentProps = {
theme: Theme;
$variant: LayoutVariant;
};

const BASE_CONTAINER_STYLES: CSSObject = {
display: "flex",
flexDirection: "column",
width: "100%",
overflowY: "auto",
};

const getContainerVariantStyles = (variant: LayoutVariant, theme: Theme) => {
const layoutVariantStylesMap: { [key in LayoutVariant]: CSSObject } = {
standard: {
...BASE_CONTAINER_STYLES,
padding: theme.spacing(theme.clutch.spacing.md),
},
wizard: {
...BASE_CONTAINER_STYLES,
width: "800px", // Taken from the Wizard Component default width
padding: theme.spacing(theme.clutch.spacing.lg, theme.clutch.spacing.none),
margin: theme.spacing(theme.clutch.spacing.none, "auto"),
},
// No styles
custom: {},
};
return layoutVariantStylesMap[variant];
};

const LayoutContainer = styled("div")(
({ $variant, theme }: StyledVariantComponentProps) =>
getContainerVariantStyles($variant, theme) as Interpolation<void>
);

const PageHeader = styled("div")(({ $variant, theme }: StyledVariantComponentProps) => ({
padding: theme.spacing(
theme.clutch.spacing.base,
$variant === "wizard" ? theme.clutch.spacing.md : theme.clutch.spacing.none
),
width: "100%",
}));

const HeaderTitle = styled(Typography)({
lineHeight: 1,
});

const WorkflowLayout = ({
variant,
heading,
hideHeader = false,
children,
}: React.PropsWithChildren<LayoutProps>) => {
return (
<LayoutContainer $variant={variant}>
{!hideHeader && (
<PageHeader $variant={variant}>
{heading && (
<>
{React.isValidElement(heading) ? (
heading
) : (
<HeaderTitle variant="h2">{heading}</HeaderTitle>
)}
</>
)}
</PageHeader>
)}
{children}
</LayoutContainer>
);
};

export default WorkflowLayout;
1 change: 1 addition & 0 deletions frontend/packages/core/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export { default as ClutchApp } from "./AppProvider";
export { useTheme } from "./AppProvider/themes";
export { ThemeProvider } from "./Theme";
export { getDisplayName } from "./utils";
export { default as WorkflowLayout } from "./WorkflowLayout";

export { css as EMOTION_CSS, keyframes as EMOTION_KEYFRAMES } from "@emotion/react";

Expand Down

0 comments on commit 3d39574

Please sign in to comment.