Skip to content

Side menu: style fixes, small improvements and better Info Panel component props #1816

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

Merged
merged 16 commits into from
Mar 24, 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
130 changes: 74 additions & 56 deletions apps/webapp/app/components/BlankStatePanels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
ServerStackIcon,
Squares2X2Icon,
} from "@heroicons/react/20/solid";
import { useLocation } from "react-use";
import { TaskIcon } from "~/assets/icons/TaskIcon";
import { useEnvironment } from "~/hooks/useEnvironment";
import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import { type MinimumEnvironment } from "~/presenters/SelectBestEnvironmentPresenter.server";
import {
docsPath,
Expand All @@ -22,20 +26,15 @@ import {
import { InlineCode } from "./code/InlineCode";
import { environmentFullTitle } from "./environments/EnvironmentLabel";
import { Feedback } from "./Feedback";
import { EnvironmentSelector } from "./navigation/EnvironmentSelector";
import { Button, LinkButton } from "./primitives/Buttons";
import { Header1 } from "./primitives/Headers";
import { InfoPanel } from "./primitives/InfoPanel";
import { Paragraph } from "./primitives/Paragraph";
import { StepNumber } from "./primitives/StepNumber";
import { TextLink } from "./primitives/TextLink";
import { InitCommandV3, PackageManagerProvider, TriggerDevStepV3 } from "./SetupCommands";
import { StepContentContainer } from "./StepContentContainer";
import { useLocation } from "react-use";
import { useEnvironment } from "~/hooks/useEnvironment";
import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import { TextLink } from "./primitives/TextLink";
import { EnvironmentSelector } from "./navigation/EnvironmentSelector";
import { Pi } from "lucide-react";

export function HasNoTasksDev() {
return (
Expand Down Expand Up @@ -79,20 +78,24 @@ export function HasNoTasksDev() {
export function HasNoTasksDeployed({ environment }: { environment: MinimumEnvironment }) {
return (
<InfoPanel
title="You don't have any deployed tasks"
title={`You don't have any deployed tasks in ${environmentFullTitle(environment)}`}
icon={TaskIcon}
iconClassName="text-blue-500"
panelClassName="max-w-full"
accessory={
<LinkButton
to={docsPath("deployment/overview")}
variant="docs/small"
LeadingIcon={BookOpenIcon}
>
How to deploy tasks
</LinkButton>
}
>
<Paragraph spacing variant="small">
You don't have any deployed tasks in {environmentFullTitle(environment)}.
Run the <TextLink to={docsPath("deployment/overview")}>CLI deploy command</TextLink> to
deploy your tasks to the {environmentFullTitle(environment)} environment.
</Paragraph>
<LinkButton
to={docsPath("deployment/overview")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
>
How to deploy tasks
</LinkButton>
</InfoPanel>
);
}
Expand All @@ -104,18 +107,20 @@ export function SchedulesNoPossibleTaskPanel() {
icon={ClockIcon}
iconClassName="text-sun-500"
panelClassName="max-w-full"
accessory={
<LinkButton
to={docsPath("v3/tasks-scheduled")}
variant="docs/small"
LeadingIcon={BookOpenIcon}
>
How to schedule tasks
</LinkButton>
}
>
<Paragraph spacing variant="small">
You have no scheduled tasks in your project. Before you can schedule a task you need to
create a <InlineCode>schedules.task</InlineCode>.
</Paragraph>
<LinkButton
to={docsPath("v3/tasks-scheduled")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
>
View the docs
</LinkButton>
</InfoPanel>
);
}
Expand All @@ -140,15 +145,16 @@ export function SchedulesNoneAttached() {
<div className="flex gap-2">
<LinkButton
to={`${v3NewSchedulePath(organization, project, environment)}${location.search}`}
variant="primary/small"
variant="secondary/medium"
LeadingIcon={RectangleGroupIcon}
className="inline-flex"
leadingIconClassName="text-sun-500"
>
Use the dashboard
</LinkButton>
<LinkButton
to={docsPath("v3/tasks-scheduled")}
variant="primary/small"
variant="docs/medium"
LeadingIcon={BookOpenIcon}
className="inline-flex"
>
Expand All @@ -166,14 +172,16 @@ export function BatchesNone() {
icon={Squares2X2Icon}
iconClassName="text-blue-500"
panelClassName="max-w-full"
accessory={
<LinkButton to={docsPath("triggering")} variant="docs/small" LeadingIcon={BookOpenIcon}>
How to trigger batches
</LinkButton>
}
>
<Paragraph spacing variant="small">
You have no batches in this environment. You can trigger batches from your backend or from
inside other tasks.
</Paragraph>
<LinkButton to={docsPath("triggering")} variant="docs/medium" LeadingIcon={BookOpenIcon}>
How to trigger batches
</LinkButton>
</InfoPanel>
);
}
Expand All @@ -182,23 +190,27 @@ export function TestHasNoTasks() {
const organization = useOrganization();
const project = useProject();
const environment = useEnvironment();

return (
<InfoPanel
title="No tasks to test"
title="You don't have any tasks to test"
icon={BeakerIcon}
iconClassName="text-lime-500"
panelClassName="max-w-full"
accessory={
<LinkButton
to={v3EnvironmentPath(organization, project, environment)}
variant="secondary/small"
LeadingIcon={PlusIcon}
>
Create a task
</LinkButton>
}
>
<Paragraph spacing variant="small">
You have no tasks in this environment.
Before testing a task, you must first create one. Follow the instructions on the{" "}
<TextLink to={v3EnvironmentPath(organization, project, environment)}>Tasks page</TextLink>{" "}
to create a task, then return here to test it.
</Paragraph>
<LinkButton
to={v3EnvironmentPath(organization, project, environment)}
variant="tertiary/medium"
>
Add tasks
</LinkButton>
</InfoPanel>
);
}
Expand Down Expand Up @@ -346,7 +358,15 @@ export function AlertsNoneDeployed() {
and webhooks.
</Paragraph>

<div className="flex gap-3">
<div className="flex items-center justify-between gap-3">
<LinkButton
to={docsPath("troubleshooting-alerts")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
className="inline-flex"
>
Alerts docs
</LinkButton>
<LinkButton
to={v3NewProjectAlertPath(organization, project, environment)}
variant="primary/medium"
Expand All @@ -355,14 +375,6 @@ export function AlertsNoneDeployed() {
>
New alert
</LinkButton>
<LinkButton
to={docsPath("troubleshooting-alerts")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
className="inline-flex"
>
Alert docs
</LinkButton>
</div>
</InfoPanel>
</div>
Expand All @@ -376,20 +388,26 @@ export function QueuesHasNoTasks() {

return (
<InfoPanel
title="You have no queues"
title="You don't have any queues"
icon={RectangleStackIcon}
iconClassName="text-purple-500"
panelClassName="max-w-full"
iconClassName="text-blue-500"
panelClassName="max-w-md"
accessory={
<LinkButton
to={v3EnvironmentPath(organization, project, environment)}
variant="secondary/small"
LeadingIcon={PlusIcon}
>
Create a task
</LinkButton>
}
>
<Paragraph spacing variant="small">
This means you haven't got any tasks yet in this environment.
Queues will appear here when you have created a task in this environment. Follow the
instructions on the{" "}
<TextLink to={v3EnvironmentPath(organization, project, environment)}>Tasks page</TextLink>{" "}
to create a task, then return here to see its queue.
</Paragraph>
<LinkButton
to={v3EnvironmentPath(organization, project, environment)}
variant="tertiary/medium"
>
Add tasks
</LinkButton>
</InfoPanel>
);
}
Expand Down
19 changes: 6 additions & 13 deletions apps/webapp/app/components/navigation/SideMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
ArrowRightOnRectangleIcon,
BeakerIcon,
BellAlertIcon,
BookOpenIcon,
ChartBarIcon,
ChevronRightIcon,
ClockIcon,
Expand Down Expand Up @@ -59,16 +58,11 @@ import {
import connectedImage from "../../assets/images/cli-connected.png";
import disconnectedImage from "../../assets/images/cli-disconnected.png";
import { FreePlanUsage } from "../billing/FreePlanUsage";
import { InlineCode } from "../code/InlineCode";
import { useDevPresence } from "../DevPresence";
import { ImpersonationBanner } from "../ImpersonationBanner";
import { Button, ButtonContent, LinkButton } from "../primitives/Buttons";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTrigger,
} from "../primitives/Dialog";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "../primitives/Dialog";
import { Paragraph } from "../primitives/Paragraph";
import {
Popover,
Expand All @@ -86,7 +80,6 @@ import { HelpAndFeedback } from "./HelpAndFeedbackPopover";
import { SideMenuHeader } from "./SideMenuHeader";
import { SideMenuItem } from "./SideMenuItem";
import { SideMenuSection } from "./SideMenuSection";
import { InlineCode } from "../code/InlineCode";

type SideMenuUser = Pick<User, "email" | "admin"> & { isImpersonating: boolean };
export type SideMenuProject = Pick<
Expand Down Expand Up @@ -280,7 +273,7 @@ function ProjectSelector({

let plan: string | undefined = undefined;
if (currentPlan?.v3Subscription?.isPaying === false) {
plan = "Free plan";
plan = "Free";
} else if (currentPlan?.v3Subscription?.isPaying === true) {
plan = currentPlan.v3Subscription.plan?.title;
}
Expand Down Expand Up @@ -326,7 +319,7 @@ function ProjectSelector({
className="text-xs"
to={v3BillingPath(organization)}
>
{plan}
{plan} plan
</TextLink>
)}
<TextLink
Expand Down Expand Up @@ -449,7 +442,7 @@ function SwitchOrganizations({
return (
<Popover onOpenChange={(open) => setMenuOpen(open)} open={isMenuOpen}>
<div onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<PopoverTrigger className="h-7 w-full justify-between overflow-hidden focus-custom">
<PopoverTrigger className="w-full justify-between overflow-hidden focus-custom">
<ButtonContent
variant="small-menu-item"
className="hover:bg-charcoal-750"
Expand All @@ -473,7 +466,7 @@ function SwitchOrganizations({
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className="p-1">
<div className="flex flex-col gap-1 p-1">
{organizations.map((org) => (
<PopoverMenuItem
key={org.id}
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/navigation/SideMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function SideMenuItem({

export function MenuCount({ count }: { count: number | string }) {
return (
<div className="rounded-full bg-charcoal-900 px-2 py-1 text-xxs uppercase tracking-wider text-text-dimmed">
<div className="rounded border border-charcoal-650 bg-background-dimmed/70 px-1.5 py-1 text-xxs uppercase tracking-wider text-text-dimmed">
{count}
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/navigation/SideMenuSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function SideMenuSection({
return (
<div>
<div
className="flex cursor-pointer items-center gap-1 rounded-sm py-1 pl-1 text-text-dimmed hover:bg-charcoal-750 hover:text-text-bright"
className="flex cursor-pointer items-center gap-1 rounded-sm py-1 pl-1 text-text-dimmed transition hover:bg-charcoal-750 hover:text-text-bright"
onClick={handleToggle}
>
<h2 className="text-xs">{title}</h2>
Expand Down
16 changes: 5 additions & 11 deletions apps/webapp/app/components/primitives/InfoPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cn } from "~/utils/cn";
import { LinkButton } from "./Buttons";
import { Header2 } from "./Headers";
import { Paragraph } from "./Paragraph";
import { type ReactNode } from "react";

const variants = {
info: {
Expand All @@ -20,8 +20,7 @@ type InfoPanelVariant = keyof typeof variants;
type Props = {
title?: string;
children: React.ReactNode;
to?: string;
buttonLabel?: string;
accessory?: ReactNode;
icon: React.ComponentType<any>;
iconClassName?: string;
variant?: InfoPanelVariant;
Expand All @@ -31,8 +30,7 @@ type Props = {
export function InfoPanel({
title,
children,
to,
buttonLabel,
accessory,
icon,
iconClassName,
variant = "info",
Expand All @@ -50,14 +48,10 @@ export function InfoPanel({
panelClassName
)}
>
<div className={cn("flex items-center gap-2", to ? "w-full justify-between" : "")}>
<div className={cn("flex items-center gap-2", accessory ? "w-full justify-between" : "")}>
<Icon className={cn("size-5", iconClassName)} />

{to && (
<LinkButton to={to} variant="secondary/small">
{buttonLabel}
</LinkButton>
)}
{accessory}
</div>
<div className="flex flex-col gap-1">
{title && <Header2 className="text-text-bright">{title}</Header2>}
Expand Down
Loading