Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fleet UI: Info banner component, uses Card as base component, tests #26276

Merged
merged 4 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions frontend/components/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Base component to reusable <InfoBanner/>, <HostCountCard/>, <SectionCard/>, etc
// and countless single use components
import React from "react";
import classnames from "classnames";

Expand All @@ -6,13 +8,13 @@ import { Link } from "react-router";
const baseClass = "card";

type BorderRadiusSize = "small" | "medium" | "large" | "xlarge" | "xxlarge";
type CardColor = "white" | "gray" | "purple" | "yellow";
type CardColor = "white" | "grey" | "purple" | "yellow";

interface ICardProps {
children?: React.ReactNode;
/** The size of the border radius. Defaults to `small`.
*
* These correspond to the boarder radius in the design system. Look at
* These correspond to the border radius in the design system. Look at
* `var/_global.scss` for values */
borderRadiusSize?: BorderRadiusSize;
/** Includes the card shadows. Defaults to `false` */
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/Card/_styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
background-color: $core-white;
}

&__gray {
&__grey {
background-color: $ui-off-white;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const FileProgressModal = ({
onExit={noop}
disableClosingModal
>
<Card color="gray" className={`${baseClass}__card`}>
<Card color="grey" className={`${baseClass}__card`}>
<FileDetails
graphicNames={graphicNames}
fileDetails={fileDetails}
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/FileUploader/FileUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export const FileUploader = ({
};

return (
<Card color="gray" className={classes}>
<Card color="grey" className={classes}>
{isFileSelected && fileDetails ? (
<FileDetails
graphicNames={graphicNames}
Expand Down
9 changes: 9 additions & 0 deletions frontend/components/InfoBanner/InfoBanner.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import { Meta, StoryObj } from "@storybook/react";
import CustomLink from "components/CustomLink";

import InfoBanner from ".";

Expand All @@ -17,5 +18,13 @@ type Story = StoryObj<typeof InfoBanner>;
export const Default: Story = {
args: {
children: <div>This is an Info Banner.</div>,
cta: (
<CustomLink
url="http://localhost:6006/"
text="Reopen Storybook"
newTab
// TODO: variant="info-banner" after merge
/>
),
},
};
30 changes: 28 additions & 2 deletions frontend/components/InfoBanner/InfoBanner.tests.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
import React from "react";

import { render, screen } from "@testing-library/react";
import { render, screen, fireEvent } from "@testing-library/react";

import InfoBanner from "./InfoBanner";

describe("InfoBanner - component", () => {
it("info banner renders text", () => {
it("renders children content", () => {
render(<InfoBanner>Info banner testing text</InfoBanner>);

const title = screen.getByText("Info banner testing text");

expect(title).toBeInTheDocument();
});

it("renders as page-level banner", () => {
const { container } = render(<InfoBanner pageLevel />);
expect(container.firstChild).toHaveClass("info-banner__page-banner");
});

it("renders CTA element", () => {
const cta = <button>Click me</button>;
render(<InfoBanner cta={cta} />);
expect(screen.getByText("Click me")).toBeInTheDocument();
});

it("renders closable button and hides banner on click", () => {
render(<InfoBanner closable>Test message</InfoBanner>);

const closeButton = screen.getByRole("button");
expect(closeButton).toBeInTheDocument();

fireEvent.click(closeButton);
expect(screen.queryByText("Test message")).not.toBeInTheDocument();
});

it("renders with icon class when icon prop is provided", () => {
const { container } = render(<InfoBanner icon="info" />);
expect(container.firstChild).toHaveClass("info-banner__icon");
});
});
32 changes: 9 additions & 23 deletions frontend/components/InfoBanner/InfoBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@ import classNames from "classnames";
import Icon from "components/Icon";
import Button from "components/buttons/Button";
import { IconNames } from "components/icons";
import Card from "components/Card";

const baseClass = "info-banner";

export interface IInfoBannerProps {
children?: React.ReactNode;
className?: string;
/** default light purple */
color?: "purple" | "purple-bold-border" | "yellow" | "grey";
color?: "purple" | "yellow" | "grey";
/** default 4px */
borderRadius?: "large" | "xlarge";
borderRadius?: "medium" | "xlarge";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

corresponds to Card border radius sizes

pageLevel?: boolean;
/** Add this element to the end of the banner message. Mutually exclusive with `link`. */
cta?: JSX.Element;
/** closable and link are mutually exclusive */
closable?: boolean;
/** Makes the entire banner clickable */
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing through instead since path is prop on Card

link?: string;
icon?: IconNames;
}

Expand All @@ -32,15 +31,11 @@ const InfoBanner = ({
pageLevel,
cta,
closable,
link,
icon,
}: IInfoBannerProps) => {
const wrapperClasses = classNames(
baseClass,
`${baseClass}__${color}`,
{
[`${baseClass}__${color}`]: !!color,
[`${baseClass}__border-radius-${borderRadius}`]: !!borderRadius,
[`${baseClass}__page-banner`]: !!pageLevel,
[`${baseClass}__icon`]: !!icon,
},
Expand Down Expand Up @@ -75,23 +70,14 @@ const InfoBanner = ({
return <></>;
}

if (link) {
return (
<a
href={link}
target="_blank"
rel="noreferrer"
className={wrapperClasses}
>
{content}
</a>
);
}

return (
<div className={wrapperClasses} role="status">
<Card
className={wrapperClasses}
color={color}
borderRadiusSize={borderRadius}
>
{content}
</div>
</Card>
);
};

Expand Down
34 changes: 2 additions & 32 deletions frontend/components/InfoBanner/_styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,16 @@
display: flex;
justify-content: space-between;
padding: $pad-medium;
border-radius: $border-radius;
border: 1px solid $ui-vibrant-blue-50;
font-size: $x-small;
font-weight: $regular;
color: $core-fleet-black;

&__purple {
background-color: $ui-vibrant-blue-10;
}

&__purple-bold-border {
background-color: $ui-vibrant-blue-10;
border-color: $core-vibrant-blue;
}

&__yellow {
background-color: $ui-yellow-banner;
border-color: $ui-yellow-banner-outline;
}

&__grey {
background-color: $ui-off-white;
border-color: $ui-fleet-black-50;
}

&__page-banner {
padding: $pad-large $pad-xlarge;
margin-bottom: $pad-large;
width: auto;
}

&__border-radius-large {
border-radius: $border-radius-medium;
}

&__border-radius-xlarge {
border-radius: $border-radius-xlarge;
}

&__info {
p {
margin: $pad-small 0 0 0;
Expand All @@ -62,9 +33,8 @@
}

&__close {
margin-left: $pad-small;
padding: $xx-small;
padding-right: 0;
padding: $pad-small;
margin: -$pad-small; // Offset clickable padding from making banner taller

&:hover {
cursor: pointer;
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/MainContent/MainContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const MainContent = ({
banner = <AppleBMTermsMessage />;
} else if (isVppExpired || willVppExpire) {
banner = <VppRenewalMessage expired={isVppExpired} />;
} else if (isFleetLicenseExpired) {
} else if (!isFleetLicenseExpired) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Change this back - used for testing

banner = <LicenseExpirationBanner />;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface IAddProfileCardProps {
}

const AddProfileCard = ({ setShowModal }: IAddProfileCardProps) => (
<Card color="gray" className={baseClass}>
<Card color="grey" className={baseClass}>
<div className={`${baseClass}__card--content-wrap`}>
<ProfileGraphic baseClass={baseClass} showMessage />
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ const AddProfileModal = ({
{isPremiumTier && !isLoadingLabels && isErrorLabels && <DataError />}
{(!isPremiumTier || (!isLoadingLabels && !isErrorLabels)) && (
<div className={`${baseClass}__modal-content-wrap`}>
<Card color="gray" className={`${baseClass}__file`}>
<Card color="grey" className={`${baseClass}__file`}>
{!fileDetails ? (
<FileChooser isLoading={isLoading} onFileOpen={onFileOpen} />
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const baseClass = "install-software-preview";

const InstallSoftwarePreview = () => {
return (
<Card color="gray" paddingSize="xxlarge" className={baseClass}>
<Card color="grey" paddingSize="xxlarge" className={baseClass}>
<h3>End user experience</h3>
<p>
After the <b>Remote Management</b> screen, the end user will see
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const baseClass = "setup-assistant-preview";

const SetupAssistantPreview = () => {
return (
<Card color="gray" paddingSize="xxlarge" className={baseClass}>
<Card color="grey" paddingSize="xxlarge" className={baseClass}>
<h3>End user experience</h3>
<p>
After the end user continues past the <b>Remote Management</b> screen,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const baseClass = "setup-experience-script-preview";

const SetupExperienceScriptPreview = () => {
return (
<Card color="gray" paddingSize="xxlarge" className={baseClass}>
<Card color="grey" paddingSize="xxlarge" className={baseClass}>
<h3>End user experience</h3>
<p>
After software is installed, the end user will see the script being run.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const FleetAppSummary = ({
<Card
className={`${baseClass}__fleet-app-summary`}
borderRadiusSize="medium"
color="gray"
color="grey"
>
<div className={`${baseClass}__fleet-app-summary--left`}>
<SoftwareIcon name={name} size="medium" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ const SoftwareInstallerCard = ({
return (
<Card borderRadiusSize="xxlarge" includeShadow className={baseClass}>
<div className={`${baseClass}__row-1`}>
{/* TODO: main-info could be a seperate component as its reused on a couple
{/* TODO: main-info could be a separate component as its reused on a couple
pages already. Come back and pull this into a component */}
<div className={`${baseClass}__main-info`}>
{renderIcon()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const SectionCard = ({
const cardClasses = classnames(baseClass, className);

return (
<Card className={cardClasses} color="gray">
<Card className={cardClasses} color="grey">
<div className={`${baseClass}__content-wrapper`}>
{iconName && <Icon name={iconName} />}
<div className={`${baseClass}__content`}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const ExampleTicket = ({
);

return (
<Card className={baseClass} color="gray">
<Card className={baseClass} color="grey">
{screenshot}
</Card>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Card from "components/Card";
import Checkbox from "components/forms/fields/Checkbox";
import Icon from "components/Icon";
import InfoBanner from "components/InfoBanner";
Expand Down Expand Up @@ -67,12 +68,12 @@ const DiscardDataOption = ({
{["differential", "differential_ignore_removals"].includes(
selectedLoggingType
) && (
<InfoBanner color="purple-bold-border">
<>
<>
<InfoBanner color="purple">
The <b>Discard data</b> setting is ignored when differential logging
is enabled. This query&apos;s results will not be saved in Fleet.
</>
</InfoBanner>
</InfoBanner>
</>
)}
<Checkbox
name="discardData"
Expand Down
Loading