Skip to content

Commit 2ef60ce

Browse files
authored
Side menu: style fixes, small improvements and better Info Panel component props (#1816)
* Adds “plan” to the plan name if it’s a paid plan so they all format correctly * Fixes menu item having incorrect height * Adds gap between switch org menu items * Moves main action button to right side in blank state * Simpler way to add “plan” to the plan name * Styled the plan badge a bit nicer * Project page now matches the other settings page layouts * Fixes colour of queue icon * Fixes table blank state not spanning enough cols * Organize imports * Unified the blank state panels and improved some copy in them * Improved the copy in the no deployed tasks blank state * Make the upgrade icon solid and indigo * Transition the hover state on the side menu section * Replaces many props with a single ‘accessory’ React node on the Info Panel component * Organize imports
1 parent c4e1364 commit 2ef60ce

File tree

16 files changed

+211
-175
lines changed

16 files changed

+211
-175
lines changed

apps/webapp/app/components/BlankStatePanels.tsx

Lines changed: 74 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import {
1010
ServerStackIcon,
1111
Squares2X2Icon,
1212
} from "@heroicons/react/20/solid";
13+
import { useLocation } from "react-use";
1314
import { TaskIcon } from "~/assets/icons/TaskIcon";
15+
import { useEnvironment } from "~/hooks/useEnvironment";
16+
import { useOrganization } from "~/hooks/useOrganizations";
17+
import { useProject } from "~/hooks/useProject";
1418
import { type MinimumEnvironment } from "~/presenters/SelectBestEnvironmentPresenter.server";
1519
import {
1620
docsPath,
@@ -22,20 +26,15 @@ import {
2226
import { InlineCode } from "./code/InlineCode";
2327
import { environmentFullTitle } from "./environments/EnvironmentLabel";
2428
import { Feedback } from "./Feedback";
29+
import { EnvironmentSelector } from "./navigation/EnvironmentSelector";
2530
import { Button, LinkButton } from "./primitives/Buttons";
2631
import { Header1 } from "./primitives/Headers";
2732
import { InfoPanel } from "./primitives/InfoPanel";
2833
import { Paragraph } from "./primitives/Paragraph";
2934
import { StepNumber } from "./primitives/StepNumber";
35+
import { TextLink } from "./primitives/TextLink";
3036
import { InitCommandV3, PackageManagerProvider, TriggerDevStepV3 } from "./SetupCommands";
3137
import { StepContentContainer } from "./StepContentContainer";
32-
import { useLocation } from "react-use";
33-
import { useEnvironment } from "~/hooks/useEnvironment";
34-
import { useOrganization } from "~/hooks/useOrganizations";
35-
import { useProject } from "~/hooks/useProject";
36-
import { TextLink } from "./primitives/TextLink";
37-
import { EnvironmentSelector } from "./navigation/EnvironmentSelector";
38-
import { Pi } from "lucide-react";
3938

4039
export function HasNoTasksDev() {
4140
return (
@@ -79,20 +78,24 @@ export function HasNoTasksDev() {
7978
export function HasNoTasksDeployed({ environment }: { environment: MinimumEnvironment }) {
8079
return (
8180
<InfoPanel
82-
title="You don't have any deployed tasks"
81+
title={`You don't have any deployed tasks in ${environmentFullTitle(environment)}`}
8382
icon={TaskIcon}
8483
iconClassName="text-blue-500"
84+
panelClassName="max-w-full"
85+
accessory={
86+
<LinkButton
87+
to={docsPath("deployment/overview")}
88+
variant="docs/small"
89+
LeadingIcon={BookOpenIcon}
90+
>
91+
How to deploy tasks
92+
</LinkButton>
93+
}
8594
>
8695
<Paragraph spacing variant="small">
87-
You don't have any deployed tasks in {environmentFullTitle(environment)}.
96+
Run the <TextLink to={docsPath("deployment/overview")}>CLI deploy command</TextLink> to
97+
deploy your tasks to the {environmentFullTitle(environment)} environment.
8898
</Paragraph>
89-
<LinkButton
90-
to={docsPath("deployment/overview")}
91-
variant="docs/medium"
92-
LeadingIcon={BookOpenIcon}
93-
>
94-
How to deploy tasks
95-
</LinkButton>
9699
</InfoPanel>
97100
);
98101
}
@@ -104,18 +107,20 @@ export function SchedulesNoPossibleTaskPanel() {
104107
icon={ClockIcon}
105108
iconClassName="text-sun-500"
106109
panelClassName="max-w-full"
110+
accessory={
111+
<LinkButton
112+
to={docsPath("v3/tasks-scheduled")}
113+
variant="docs/small"
114+
LeadingIcon={BookOpenIcon}
115+
>
116+
How to schedule tasks
117+
</LinkButton>
118+
}
107119
>
108120
<Paragraph spacing variant="small">
109121
You have no scheduled tasks in your project. Before you can schedule a task you need to
110122
create a <InlineCode>schedules.task</InlineCode>.
111123
</Paragraph>
112-
<LinkButton
113-
to={docsPath("v3/tasks-scheduled")}
114-
variant="docs/medium"
115-
LeadingIcon={BookOpenIcon}
116-
>
117-
View the docs
118-
</LinkButton>
119124
</InfoPanel>
120125
);
121126
}
@@ -140,15 +145,16 @@ export function SchedulesNoneAttached() {
140145
<div className="flex gap-2">
141146
<LinkButton
142147
to={`${v3NewSchedulePath(organization, project, environment)}${location.search}`}
143-
variant="primary/small"
148+
variant="secondary/medium"
144149
LeadingIcon={RectangleGroupIcon}
145150
className="inline-flex"
151+
leadingIconClassName="text-sun-500"
146152
>
147153
Use the dashboard
148154
</LinkButton>
149155
<LinkButton
150156
to={docsPath("v3/tasks-scheduled")}
151-
variant="primary/small"
157+
variant="docs/medium"
152158
LeadingIcon={BookOpenIcon}
153159
className="inline-flex"
154160
>
@@ -166,14 +172,16 @@ export function BatchesNone() {
166172
icon={Squares2X2Icon}
167173
iconClassName="text-blue-500"
168174
panelClassName="max-w-full"
175+
accessory={
176+
<LinkButton to={docsPath("triggering")} variant="docs/small" LeadingIcon={BookOpenIcon}>
177+
How to trigger batches
178+
</LinkButton>
179+
}
169180
>
170181
<Paragraph spacing variant="small">
171182
You have no batches in this environment. You can trigger batches from your backend or from
172183
inside other tasks.
173184
</Paragraph>
174-
<LinkButton to={docsPath("triggering")} variant="docs/medium" LeadingIcon={BookOpenIcon}>
175-
How to trigger batches
176-
</LinkButton>
177185
</InfoPanel>
178186
);
179187
}
@@ -182,23 +190,27 @@ export function TestHasNoTasks() {
182190
const organization = useOrganization();
183191
const project = useProject();
184192
const environment = useEnvironment();
185-
186193
return (
187194
<InfoPanel
188-
title="No tasks to test"
195+
title="You don't have any tasks to test"
189196
icon={BeakerIcon}
190197
iconClassName="text-lime-500"
191198
panelClassName="max-w-full"
199+
accessory={
200+
<LinkButton
201+
to={v3EnvironmentPath(organization, project, environment)}
202+
variant="secondary/small"
203+
LeadingIcon={PlusIcon}
204+
>
205+
Create a task
206+
</LinkButton>
207+
}
192208
>
193209
<Paragraph spacing variant="small">
194-
You have no tasks in this environment.
210+
Before testing a task, you must first create one. Follow the instructions on the{" "}
211+
<TextLink to={v3EnvironmentPath(organization, project, environment)}>Tasks page</TextLink>{" "}
212+
to create a task, then return here to test it.
195213
</Paragraph>
196-
<LinkButton
197-
to={v3EnvironmentPath(organization, project, environment)}
198-
variant="tertiary/medium"
199-
>
200-
Add tasks
201-
</LinkButton>
202214
</InfoPanel>
203215
);
204216
}
@@ -346,7 +358,15 @@ export function AlertsNoneDeployed() {
346358
and webhooks.
347359
</Paragraph>
348360

349-
<div className="flex gap-3">
361+
<div className="flex items-center justify-between gap-3">
362+
<LinkButton
363+
to={docsPath("troubleshooting-alerts")}
364+
variant="docs/medium"
365+
LeadingIcon={BookOpenIcon}
366+
className="inline-flex"
367+
>
368+
Alerts docs
369+
</LinkButton>
350370
<LinkButton
351371
to={v3NewProjectAlertPath(organization, project, environment)}
352372
variant="primary/medium"
@@ -355,14 +375,6 @@ export function AlertsNoneDeployed() {
355375
>
356376
New alert
357377
</LinkButton>
358-
<LinkButton
359-
to={docsPath("troubleshooting-alerts")}
360-
variant="docs/medium"
361-
LeadingIcon={BookOpenIcon}
362-
className="inline-flex"
363-
>
364-
Alert docs
365-
</LinkButton>
366378
</div>
367379
</InfoPanel>
368380
</div>
@@ -376,20 +388,26 @@ export function QueuesHasNoTasks() {
376388

377389
return (
378390
<InfoPanel
379-
title="You have no queues"
391+
title="You don't have any queues"
380392
icon={RectangleStackIcon}
381-
iconClassName="text-purple-500"
382-
panelClassName="max-w-full"
393+
iconClassName="text-blue-500"
394+
panelClassName="max-w-md"
395+
accessory={
396+
<LinkButton
397+
to={v3EnvironmentPath(organization, project, environment)}
398+
variant="secondary/small"
399+
LeadingIcon={PlusIcon}
400+
>
401+
Create a task
402+
</LinkButton>
403+
}
383404
>
384405
<Paragraph spacing variant="small">
385-
This means you haven't got any tasks yet in this environment.
406+
Queues will appear here when you have created a task in this environment. Follow the
407+
instructions on the{" "}
408+
<TextLink to={v3EnvironmentPath(organization, project, environment)}>Tasks page</TextLink>{" "}
409+
to create a task, then return here to see its queue.
386410
</Paragraph>
387-
<LinkButton
388-
to={v3EnvironmentPath(organization, project, environment)}
389-
variant="tertiary/medium"
390-
>
391-
Add tasks
392-
</LinkButton>
393411
</InfoPanel>
394412
);
395413
}

apps/webapp/app/components/navigation/SideMenu.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
ArrowRightOnRectangleIcon,
44
BeakerIcon,
55
BellAlertIcon,
6-
BookOpenIcon,
76
ChartBarIcon,
87
ChevronRightIcon,
98
ClockIcon,
@@ -59,16 +58,11 @@ import {
5958
import connectedImage from "../../assets/images/cli-connected.png";
6059
import disconnectedImage from "../../assets/images/cli-disconnected.png";
6160
import { FreePlanUsage } from "../billing/FreePlanUsage";
61+
import { InlineCode } from "../code/InlineCode";
6262
import { useDevPresence } from "../DevPresence";
6363
import { ImpersonationBanner } from "../ImpersonationBanner";
6464
import { Button, ButtonContent, LinkButton } from "../primitives/Buttons";
65-
import {
66-
Dialog,
67-
DialogContent,
68-
DialogFooter,
69-
DialogHeader,
70-
DialogTrigger,
71-
} from "../primitives/Dialog";
65+
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "../primitives/Dialog";
7266
import { Paragraph } from "../primitives/Paragraph";
7367
import {
7468
Popover,
@@ -86,7 +80,6 @@ import { HelpAndFeedback } from "./HelpAndFeedbackPopover";
8680
import { SideMenuHeader } from "./SideMenuHeader";
8781
import { SideMenuItem } from "./SideMenuItem";
8882
import { SideMenuSection } from "./SideMenuSection";
89-
import { InlineCode } from "../code/InlineCode";
9083

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

281274
let plan: string | undefined = undefined;
282275
if (currentPlan?.v3Subscription?.isPaying === false) {
283-
plan = "Free plan";
276+
plan = "Free";
284277
} else if (currentPlan?.v3Subscription?.isPaying === true) {
285278
plan = currentPlan.v3Subscription.plan?.title;
286279
}
@@ -326,7 +319,7 @@ function ProjectSelector({
326319
className="text-xs"
327320
to={v3BillingPath(organization)}
328321
>
329-
{plan}
322+
{plan} plan
330323
</TextLink>
331324
)}
332325
<TextLink
@@ -449,7 +442,7 @@ function SwitchOrganizations({
449442
return (
450443
<Popover onOpenChange={(open) => setMenuOpen(open)} open={isMenuOpen}>
451444
<div onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
452-
<PopoverTrigger className="h-7 w-full justify-between overflow-hidden focus-custom">
445+
<PopoverTrigger className="w-full justify-between overflow-hidden focus-custom">
453446
<ButtonContent
454447
variant="small-menu-item"
455448
className="hover:bg-charcoal-750"
@@ -473,7 +466,7 @@ function SwitchOrganizations({
473466
onMouseEnter={handleMouseEnter}
474467
onMouseLeave={handleMouseLeave}
475468
>
476-
<div className="p-1">
469+
<div className="flex flex-col gap-1 p-1">
477470
{organizations.map((org) => (
478471
<PopoverMenuItem
479472
key={org.id}

apps/webapp/app/components/navigation/SideMenuItem.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export function SideMenuItem({
5656

5757
export function MenuCount({ count }: { count: number | string }) {
5858
return (
59-
<div className="rounded-full bg-charcoal-900 px-2 py-1 text-xxs uppercase tracking-wider text-text-dimmed">
59+
<div className="rounded border border-charcoal-650 bg-background-dimmed/70 px-1.5 py-1 text-xxs uppercase tracking-wider text-text-dimmed">
6060
{count}
6161
</div>
6262
);

apps/webapp/app/components/navigation/SideMenuSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function SideMenuSection({
2929
return (
3030
<div>
3131
<div
32-
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"
32+
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"
3333
onClick={handleToggle}
3434
>
3535
<h2 className="text-xs">{title}</h2>

apps/webapp/app/components/primitives/InfoPanel.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { cn } from "~/utils/cn";
2-
import { LinkButton } from "./Buttons";
32
import { Header2 } from "./Headers";
43
import { Paragraph } from "./Paragraph";
4+
import { type ReactNode } from "react";
55

66
const variants = {
77
info: {
@@ -20,8 +20,7 @@ type InfoPanelVariant = keyof typeof variants;
2020
type Props = {
2121
title?: string;
2222
children: React.ReactNode;
23-
to?: string;
24-
buttonLabel?: string;
23+
accessory?: ReactNode;
2524
icon: React.ComponentType<any>;
2625
iconClassName?: string;
2726
variant?: InfoPanelVariant;
@@ -31,8 +30,7 @@ type Props = {
3130
export function InfoPanel({
3231
title,
3332
children,
34-
to,
35-
buttonLabel,
33+
accessory,
3634
icon,
3735
iconClassName,
3836
variant = "info",
@@ -50,14 +48,10 @@ export function InfoPanel({
5048
panelClassName
5149
)}
5250
>
53-
<div className={cn("flex items-center gap-2", to ? "w-full justify-between" : "")}>
51+
<div className={cn("flex items-center gap-2", accessory ? "w-full justify-between" : "")}>
5452
<Icon className={cn("size-5", iconClassName)} />
5553

56-
{to && (
57-
<LinkButton to={to} variant="secondary/small">
58-
{buttonLabel}
59-
</LinkButton>
60-
)}
54+
{accessory}
6155
</div>
6256
<div className="flex flex-col gap-1">
6357
{title && <Header2 className="text-text-bright">{title}</Header2>}

0 commit comments

Comments
 (0)