Skip to content

Commit

Permalink
Migrate Breadcrumbs to Ant
Browse files Browse the repository at this point in the history
  • Loading branch information
gilluminate committed Dec 16, 2024
1 parent a74d946 commit 4fbb8dd
Show file tree
Hide file tree
Showing 69 changed files with 970 additions and 1,023 deletions.
3 changes: 2 additions & 1 deletion clients/admin-ui/src/features/common/FixedLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const FixedLayout = ({
<link rel="icon" href="/favicon.ico" />
</Head>
<Flex
pt={6}
px={10}
py={6}
as="main"
overflow="auto"
direction="column"
Expand Down
81 changes: 51 additions & 30 deletions clients/admin-ui/src/features/common/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,75 @@
import { Box, BoxProps, Flex } from "fidesui";
import { isArray } from "lodash";
import { isValidElement, ReactElement } from "react";
import { AntFlex as Flex, AntFlexProps as FlexProps, Heading } from "fidesui";
import { ReactNode } from "react";

import Breadcrumbs, { BreadcrumbsProps } from "~/features/common/Breadcrumbs";
import { NextBreadcrumb, NextBreadcrumbProps } from "./nav/v2/NextBreadcrumb";

interface PageHeaderProps extends BoxProps {
breadcrumbs: BreadcrumbsProps["breadcrumbs"] | ReactElement | false;
interface PageHeaderProps extends Omit<FlexProps, "children"> {
heading?: ReactNode;
breadcrumbItems?: NextBreadcrumbProps["items"];
isSticky?: boolean;
rightContent?: ReactElement;
rightContent?: ReactNode;
children?: ReactNode;
}

/**
* A header component for pages.
*
* @param breadcrumbs - The breadcrumbs to display in the page header.
* @param heading - The main heading to display in the page header. Can be a string or a React element. String will be rendered as an H1.
* @param breadcrumbItems - Extends Ant Design Breadcrumb component `items` property. If an item has a `href` property, it will be wrapped in a Next.js link.
* Can be an array of breadcrumb items (more information on Breadcrumbs component), a React element
* if you want to render something else, or false to not show any breadcrumbs.
* @param isSticky - Whether the page header should stick to the top of the page while scrolling. Defaults to true.
* @param children - Additional content to display in the header at the bottom.
* @param children - Additional content to display in the header below the heading and breadcrumb.
* @param rightContent - Additional content to display in the header on the right side. Usually for displaying buttons.
*/
const PageHeader = ({
breadcrumbs,
isSticky = true,
heading,
breadcrumbItems,
isSticky,
children,
rightContent,
...otherProps
style,
...props
}: PageHeaderProps): JSX.Element => (
<Box
bgColor="white"
paddingY={5}
{...(isSticky ? { position: "sticky", top: 0, left: 0, zIndex: 10 } : {})}
{...otherProps}
<Flex
className="pb-6"
{...props}
style={
isSticky
? {
position: "sticky",
top: 0,
left: 0,
zIndex: 20,
backgroundColor: "white",
...style,
}
: style
}
>
<Flex alignItems="flex-start">
<Box flex={1}>
{/* If breadcrumbs is an array, render the Breadcrumbs component. */}
{isArray(breadcrumbs) && (
<Box marginBottom={children ? 4 : 0}>
<Breadcrumbs breadcrumbs={breadcrumbs} />
</Box>
)}
{/* If breadcrumbs is a React element, render it. */}
{isValidElement(breadcrumbs) && breadcrumbs}
</Box>
{rightContent && <Box>{rightContent}</Box>}
<Flex justify="space-between">
{typeof heading === "string" ? (
<Heading
className={!!breadcrumbItems || !!children ? "pb-4" : undefined}
fontSize="2xl"
>
{heading}
</Heading>
) : (
heading
)}
{rightContent && <div>{rightContent}</div>}
</Flex>

{!!breadcrumbItems && (
<NextBreadcrumb
className={children ? "pb-4" : undefined}
items={breadcrumbItems}
/>
)}

{children}
</Box>
</Flex>
);

export default PageHeader;
52 changes: 52 additions & 0 deletions clients/admin-ui/src/features/common/nav/v2/NextBreadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable tailwindcss/no-custom-classname */
/* eslint-disable no-param-reassign */
import {
AntBreadcrumb as Breadcrumb,
AntBreadcrumbItemType as BreadcrumbItemType,
AntBreadcrumbProps as BreadcrumbProps,
} from "fidesui";
import { Url } from "next/dist/shared/lib/router/router";
import NextLink from "next/link";
import { ReactNode } from "react";

// Too difficult to make `path` work with Next.js links so we'll just remove it from the type
interface NextBreadcrumbItemType
extends Omit<BreadcrumbItemType, "path" | "href"> {
/**
* becomes NextJS link href
*/
href?: Url;
icon?: ReactNode;
}

export interface NextBreadcrumbProps extends Omit<BreadcrumbProps, "items"> {
items?: NextBreadcrumbItemType[];
}

/**
* Extends the Ant Design Breadcrumb component to allow for Next.js links. If an item has a `href` property, it will be wrapped in a Next.js link.
* @returns
*/
export const NextBreadcrumb = ({ items, ...props }: NextBreadcrumbProps) => {
items?.map((item) => {
if (item.icon && typeof item.title === "string") {
item.title = (
<>
<span className="anticon align-text-bottom">{item.icon}</span>
<span>{item.title}</span>
</>
);
}
if (item.href && item.title) {
item.title = (
<NextLink href={item.href} className="ant-breadcrumb-link">
{item.title}
</NextLink>
);
delete item.href;
}
return item;
});
const newItems = items as BreadcrumbItemType[];
return <Breadcrumb items={newItems} {...props} />;
};
2 changes: 1 addition & 1 deletion clients/admin-ui/src/features/config-wizard/AddSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const AddSystem = () => {
return (
<Stack spacing={9} data-testid="add-systems">
<Stack spacing={6} maxWidth="600px">
<Heading as="h3" size="lg" fontWeight="semibold">
<Heading as="h3" size="md" fontWeight="semibold">
Fides helps you map your systems to manage your privacy
</Heading>
<Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AntButton as Button, Heading, HStack, Stack } from "fidesui";
import { AntButton as Button, Box, HStack, Stack, Text } from "fidesui";
import { Form, Formik } from "formik";
import { useState } from "react";
import * as Yup from "yup";
Expand All @@ -20,6 +20,7 @@ import {
import { RTKErrorResult } from "~/types/errors";

import { ControlledSelect } from "../common/form/ControlledSelect";
import { NextBreadcrumb } from "../common/nav/v2/NextBreadcrumb";
import {
changeStep,
selectOrganizationFidesKey,
Expand Down Expand Up @@ -129,12 +130,27 @@ const AuthenticateAwsForm = () => {
) : null}
{!isSubmitting && !scannerError ? (
<>
<Heading size="lg">Authenticate AWS Scanner</Heading>
<h2>
To use the scanner to inventory systems in AWS, you must first
authenticate to your AWS cloud by providing the following
information:
</h2>
<Box>
<NextBreadcrumb
className="mb-4"
items={[
{
title: "Add systems",
href: "",
onClick: (e) => {
e.preventDefault();
handleCancel();
},
},
{ title: "Authenticate AWS Scanner" },
]}
/>
<Text>
To use the scanner to inventory systems in AWS, you must
first authenticate to your AWS cloud by providing the
following information:
</Text>
</Box>
<Stack>
<CustomTextInput
name="aws_access_key_id"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AntButton as Button, Heading, HStack, Stack } from "fidesui";
import { AntButton as Button, Box, HStack, Stack, Text } from "fidesui";
import { Form, Formik } from "formik";
import { useState } from "react";
import * as Yup from "yup";
Expand All @@ -19,6 +19,7 @@ import {
} from "~/types/api";
import { RTKErrorResult } from "~/types/errors";

import { NextBreadcrumb } from "../common/nav/v2/NextBreadcrumb";
import {
changeStep,
selectOrganizationFidesKey,
Expand Down Expand Up @@ -113,12 +114,27 @@ const AuthenticateOktaForm = () => {
{scannerError ? <ScannerError error={scannerError} /> : null}
{!isSubmitting && !scannerError ? (
<>
<Heading size="lg">Authenticate Okta Scanner</Heading>
<h2>
To use the scanner to inventory systems in Okta, you must
first authenticate to your Okta account by providing the
following information:
</h2>
<Box>
<NextBreadcrumb
className="mb-4"
items={[
{
title: "Add systems",
href: "",
onClick: (e) => {
e.preventDefault();
handleCancel();
},
},
{ title: "Authenticate Okta Scanner" },
]}
/>
<Text>
To use the scanner to inventory systems in Okta, you must
first authenticate to your Okta account by providing the
following information:
</Text>
</Box>
<Stack>
<CustomTextInput
name="orgUrl"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const ConfigWizardWalkthrough = () => {

return (
<Stack direction={["column", "row"]} bg="white">
<Box display="flex" justifyContent="center" w="100%">
<Box display="flex" justifyContent="flex-start" w="100%">
{step === 1 ? <OrganizationInfoForm /> : null}
{step === 2 ? <AddSystem /> : null}
{step === 3 ? <AuthenticateScanner /> : null}
Expand Down
22 changes: 17 additions & 5 deletions clients/admin-ui/src/features/config-wizard/ScanResults.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
AntButton as Button,
Box,
Heading,
HStack,
Stack,
Text,
Expand All @@ -22,6 +21,7 @@ import { SystemsCheckboxTable } from "~/features/common/SystemsCheckboxTable";
import { useUpsertSystemsMutation } from "~/features/system";
import { System } from "~/types/api";

import { NextBreadcrumb } from "../common/nav/v2/NextBreadcrumb";
import {
changeStep,
reset,
Expand Down Expand Up @@ -95,10 +95,22 @@ const ScanResults = () => {

return (
<Box maxW="full">
<Stack spacing={10}>
<Heading as="h3" size="lg" data-testid="scan-results">
Scan results
</Heading>
<Stack spacing={10} data-testid="scan-results">
<NextBreadcrumb
className="mb-4"
items={[
{
title: "Add systems",
href: "",
onClick: (e) => {
e.preventDefault();
handleCancel();
},
},
{ title: "Authenticate" },
{ title: "Scan results" },
]}
/>

{systems.length === 0 ? (
<>
Expand Down
Loading

0 comments on commit 4fbb8dd

Please sign in to comment.