Skip to content

Commit a2b66ab

Browse files
committed
Makes the DevConnection component reusable and moves components to the DevPresence.tsx file
1 parent a03c588 commit a2b66ab

File tree

2 files changed

+145
-94
lines changed

2 files changed

+145
-94
lines changed

apps/webapp/app/components/DevPresence.tsx

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1+
import { AnimatePresence, motion } from "framer-motion";
12
import { createContext, type ReactNode, useContext, useEffect, useMemo, useState } from "react";
3+
import {
4+
CheckingConnectionIcon,
5+
ConnectedIcon,
6+
DisconnectedIcon,
7+
} from "~/assets/icons/ConnectionIcons";
28
import { useEnvironment } from "~/hooks/useEnvironment";
39
import { useEventSource } from "~/hooks/useEventSource";
410
import { useOrganization } from "~/hooks/useOrganizations";
511
import { useProject } from "~/hooks/useProject";
12+
import { docsPath } from "~/utils/pathBuilder";
13+
import connectedImage from "../assets/images/cli-connected.png";
14+
import disconnectedImage from "../assets/images/cli-disconnected.png";
15+
import { InlineCode } from "./code/InlineCode";
16+
import { Button } from "./primitives/Buttons";
17+
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "./primitives/Dialog";
18+
import { Paragraph } from "./primitives/Paragraph";
19+
import { TextLink } from "./primitives/TextLink";
20+
import { PackageManagerProvider, TriggerDevStepV3 } from "./SetupCommands";
621

722
// Define Context types
823
type DevPresenceContextType = {
@@ -77,3 +92,100 @@ export function useDevPresence() {
7792
}
7893
return context;
7994
}
95+
96+
export function ConnectionIcon({ isConnected }: { isConnected: boolean | undefined }) {
97+
if (isConnected === undefined) {
98+
return <CheckingConnectionIcon className="size-5" />;
99+
}
100+
return isConnected ? (
101+
<ConnectedIcon className="size-5" />
102+
) : (
103+
<DisconnectedIcon className="size-5" />
104+
);
105+
}
106+
107+
export function DevConnection({
108+
children,
109+
}: {
110+
children: (props: { isConnected: boolean | undefined }) => React.ReactNode;
111+
}) {
112+
const { isConnected } = useDevPresence();
113+
114+
return (
115+
<Dialog>
116+
{children({ isConnected })}
117+
<DialogContent>
118+
<DialogHeader>
119+
{isConnected === undefined
120+
? "Checking connection..."
121+
: isConnected
122+
? "Your dev server is connected"
123+
: "Your dev server is not connected"}
124+
</DialogHeader>
125+
<div className="mt-2 flex flex-col gap-3 px-2">
126+
<div className="flex flex-col items-center justify-center gap-6 px-6 py-10">
127+
<img
128+
src={isConnected === true ? connectedImage : disconnectedImage}
129+
alt={isConnected === true ? "Connected" : "Disconnected"}
130+
width={282}
131+
height={45}
132+
/>
133+
<Paragraph variant="small" className={isConnected ? "text-success" : "text-error"}>
134+
{isConnected === undefined
135+
? "Checking connection..."
136+
: isConnected
137+
? "Your local dev server is connected to Trigger.dev"
138+
: "Your local dev server is not connected to Trigger.dev"}
139+
</Paragraph>
140+
</div>
141+
{isConnected ? null : (
142+
<div className="space-y-3">
143+
<PackageManagerProvider>
144+
<TriggerDevStepV3 title="Run this command to connect" />
145+
</PackageManagerProvider>
146+
<Paragraph variant="small">
147+
Run this CLI <InlineCode variant="extra-small">dev</InlineCode> command to connect
148+
to the Trigger.dev servers to start developing locally. Keep it running while you
149+
develop to stay connected. Learn more in the{" "}
150+
<TextLink to={docsPath("cli-dev")}>CLI docs</TextLink>.
151+
</Paragraph>
152+
</div>
153+
)}
154+
</div>
155+
</DialogContent>
156+
</Dialog>
157+
);
158+
}
159+
160+
export function DevPresenceBanner() {
161+
const environment = useEnvironment();
162+
const { isConnected } = useDevPresence();
163+
164+
return (
165+
<AnimatePresence>
166+
{environment.type === "DEVELOPMENT" && !isConnected && (
167+
<motion.div
168+
initial={{ opacity: 0 }}
169+
animate={{ opacity: 1 }}
170+
exit={{ opacity: 0 }}
171+
transition={{ duration: 0.3 }}
172+
className="flex"
173+
>
174+
<DevConnection>
175+
{({ isConnected }) => (
176+
<DialogTrigger asChild>
177+
<Button
178+
variant="minimal/small"
179+
className="py-1 pl-1 pr-2 text-error"
180+
LeadingIcon={<ConnectionIcon isConnected={isConnected} />}
181+
>
182+
Your local dev server is not connected to Trigger.dev
183+
</Button>
184+
</DialogTrigger>
185+
)}
186+
</DevConnection>
187+
</motion.div>
188+
)}
189+
</AnimatePresence>
190+
);
191+
}

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

Lines changed: 33 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,9 @@ import {
2020
import { useNavigation } from "@remix-run/react";
2121
import { useEffect, useRef, useState, type ReactNode } from "react";
2222
import simplur from "simplur";
23-
import {
24-
CheckingConnectionIcon,
25-
ConnectedIcon,
26-
DisconnectedIcon,
27-
} from "~/assets/icons/ConnectionIcons";
28-
import { RunsIconExtraSmall, RunsIconSmall } from "~/assets/icons/RunsIcon";
23+
import { RunsIconExtraSmall } from "~/assets/icons/RunsIcon";
2924
import { TaskIconSmall } from "~/assets/icons/TaskIcon";
25+
import { WaitpointTokenIcon } from "~/assets/icons/WaitpointTokenIcon";
3026
import { Avatar } from "~/components/primitives/Avatar";
3127
import { type MatchedEnvironment } from "~/hooks/useEnvironment";
3228
import { type MatchedOrganization } from "~/hooks/useOrganizations";
@@ -37,7 +33,6 @@ import { type FeedbackType } from "~/routes/resources.feedback";
3733
import { cn } from "~/utils/cn";
3834
import {
3935
accountPath,
40-
docsPath,
4136
logoutPath,
4237
newOrganizationPath,
4338
newProjectPath,
@@ -60,14 +55,12 @@ import {
6055
v3UsagePath,
6156
v3WaitpointTokensPath,
6257
} from "~/utils/pathBuilder";
63-
import connectedImage from "../../assets/images/cli-connected.png";
64-
import disconnectedImage from "../../assets/images/cli-disconnected.png";
58+
6559
import { FreePlanUsage } from "../billing/FreePlanUsage";
66-
import { InlineCode } from "../code/InlineCode";
67-
import { useDevPresence } from "../DevPresence";
60+
import { ConnectionIcon, DevConnection } from "../DevPresence";
6861
import { ImpersonationBanner } from "../ImpersonationBanner";
6962
import { Button, ButtonContent, LinkButton } from "../primitives/Buttons";
70-
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "../primitives/Dialog";
63+
import { DialogTrigger } from "../primitives/Dialog";
7164
import { Paragraph } from "../primitives/Paragraph";
7265
import {
7366
Popover,
@@ -78,15 +71,12 @@ import {
7871
} from "../primitives/Popover";
7972
import { TextLink } from "../primitives/TextLink";
8073
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../primitives/Tooltip";
81-
import { PackageManagerProvider, TriggerDevStepV3 } from "../SetupCommands";
8274
import { UserProfilePhoto } from "../UserProfilePhoto";
8375
import { EnvironmentSelector } from "./EnvironmentSelector";
8476
import { HelpAndFeedback } from "./HelpAndFeedbackPopover";
8577
import { SideMenuHeader } from "./SideMenuHeader";
8678
import { SideMenuItem } from "./SideMenuItem";
8779
import { SideMenuSection } from "./SideMenuSection";
88-
import { WaitpointTokenIcon } from "~/assets/icons/WaitpointTokenIcon";
89-
import { Spinner } from "../primitives/Spinner";
9080

9181
type SideMenuUser = Pick<User, "email" | "admin"> & { isImpersonating: boolean };
9282
export type SideMenuProject = Pick<
@@ -163,7 +153,34 @@ export function SideMenu({
163153
project={project}
164154
environment={environment}
165155
/>
166-
{environment.type === "DEVELOPMENT" && <DevConnection />}
156+
{environment.type === "DEVELOPMENT" && (
157+
<DevConnection>
158+
{({ isConnected }) => (
159+
<TooltipProvider disableHoverableContent={true}>
160+
<Tooltip>
161+
<TooltipTrigger asChild>
162+
<div className="inline-flex">
163+
<DialogTrigger asChild>
164+
<Button
165+
variant="minimal/small"
166+
className="aspect-square h-7 p-1"
167+
LeadingIcon={<ConnectionIcon isConnected={isConnected} />}
168+
/>
169+
</DialogTrigger>
170+
</div>
171+
</TooltipTrigger>
172+
<TooltipContent side="right" className={"text-xs"}>
173+
{isConnected === undefined
174+
? "Checking connection..."
175+
: isConnected
176+
? "Your dev server is connected"
177+
: "Your dev server is not connected"}
178+
</TooltipContent>
179+
</Tooltip>
180+
</TooltipProvider>
181+
)}
182+
</DevConnection>
183+
)}
167184
</div>
168185
</div>
169186

@@ -522,81 +539,3 @@ function SelectorDivider() {
522539
</svg>
523540
);
524541
}
525-
526-
export function DevConnection() {
527-
const { isConnected } = useDevPresence();
528-
529-
return (
530-
<Dialog>
531-
<TooltipProvider disableHoverableContent={true}>
532-
<Tooltip>
533-
<TooltipTrigger asChild>
534-
<div className="inline-flex">
535-
<DialogTrigger asChild>
536-
<Button
537-
variant="minimal/small"
538-
className="aspect-square h-7 p-1"
539-
LeadingIcon={
540-
isConnected === undefined ? (
541-
<CheckingConnectionIcon className="size-5" />
542-
) : isConnected ? (
543-
<ConnectedIcon className="size-5" />
544-
) : (
545-
<DisconnectedIcon className="size-5" />
546-
)
547-
}
548-
/>
549-
</DialogTrigger>
550-
</div>
551-
</TooltipTrigger>
552-
<TooltipContent side="right" className={"text-xs"}>
553-
{isConnected === undefined
554-
? "Checking connection..."
555-
: isConnected
556-
? "Your dev server is connected"
557-
: "Your dev server is not connected"}
558-
</TooltipContent>
559-
</Tooltip>
560-
</TooltipProvider>
561-
<DialogContent>
562-
<DialogHeader>
563-
{isConnected === undefined
564-
? "Checking connection..."
565-
: isConnected
566-
? "Your dev server is connected"
567-
: "Your dev server is not connected"}
568-
</DialogHeader>
569-
<div className="mt-2 flex flex-col gap-3 px-2">
570-
<div className="flex flex-col items-center justify-center gap-6 px-6 py-10">
571-
<img
572-
src={isConnected === true ? connectedImage : disconnectedImage}
573-
alt={isConnected === true ? "Connected" : "Disconnected"}
574-
width={282}
575-
height={45}
576-
/>
577-
<Paragraph variant="small" className={isConnected ? "text-success" : "text-error"}>
578-
{isConnected === undefined
579-
? "Checking connection..."
580-
: isConnected
581-
? "Your local dev server is connected to Trigger.dev"
582-
: "Your local dev server is not connected to Trigger.dev"}
583-
</Paragraph>
584-
</div>
585-
{isConnected ? null : (
586-
<div className="space-y-3">
587-
<PackageManagerProvider>
588-
<TriggerDevStepV3 title="Run this command to connect" />
589-
</PackageManagerProvider>
590-
<Paragraph variant="small">
591-
Run this CLI <InlineCode variant="extra-small">dev</InlineCode> command to connect
592-
to the Trigger.dev servers to start developing locally. Keep it running while you
593-
develop to stay connected. Learn more in the{" "}
594-
<TextLink to={docsPath("cli-dev")}>CLI docs</TextLink>.
595-
</Paragraph>
596-
</div>
597-
)}
598-
</div>
599-
</DialogContent>
600-
</Dialog>
601-
);
602-
}

0 commit comments

Comments
 (0)