Skip to content

Commit 174484f

Browse files
authored
Added default time period to Runs, Waitpoint and Batch list pages. Improved dev presence (#1832)
* New time period filter (permanently displayed) * Batches, and fix for blank state * Waitpoint token filtering * Tags query: remove things we’re not using * Run tag and waitpoint tags use startsWith for faster search * Fix for run page on wrong env. Added schedule last triggered column * Removed the Redis pubsub, just use the presence key * Improve the dev presence responsiveness * The CLI presence connection recovers when the webapp is restarted * Dev schedules are now working for v4 * Refactored to make the dev presence stuff * Got rid of stupid extra /dev, added a connecting state with icon * Remove unused Redis client
1 parent 589f7c3 commit 174484f

File tree

37 files changed

+665
-665
lines changed

37 files changed

+665
-665
lines changed

apps/webapp/app/assets/icons/ConnectionIcons.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,25 @@ export function DisconnectedIcon({ className }: { className?: string }) {
4646
</svg>
4747
);
4848
}
49+
50+
export function CheckingConnectionIcon({ className }: { className?: string }) {
51+
return (
52+
<svg className={className} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
53+
<rect
54+
x="0.5"
55+
y="-0.5"
56+
width="19"
57+
height="1"
58+
rx="0.5"
59+
transform="matrix(1 0 0 -1 1.99998 20)"
60+
stroke="#878C99"
61+
/>
62+
<path
63+
fillRule="evenodd"
64+
clipRule="evenodd"
65+
d="M18 6.5L6.00001 6.5C5.72387 6.5 5.50001 6.72386 5.50001 7L5.50001 15C5.50001 15.2761 5.72387 15.5 6.00001 15.5L18 15.5C18.2762 15.5 18.5 15.2761 18.5 15V7C18.5 6.72386 18.2762 6.5 18 6.5ZM6.00001 5C4.89545 5 4.00001 5.89543 4.00001 7L4.00001 15C4.00001 16.1046 4.89545 17 6.00001 17L18 17C19.1046 17 20 16.1046 20 15V7C20 5.89543 19.1046 5 18 5L6.00001 5Z"
66+
fill="#878C99"
67+
/>
68+
</svg>
69+
);
70+
}

apps/webapp/app/components/DevPresence.tsx

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import { createContext, type ReactNode, useContext, useEffect, useMemo, useState } from "react";
2-
import { useDebounce } from "~/hooks/useDebounce";
32
import { useEnvironment } from "~/hooks/useEnvironment";
43
import { useEventSource } from "~/hooks/useEventSource";
54
import { useOrganization } from "~/hooks/useOrganizations";
65
import { useProject } from "~/hooks/useProject";
76

87
// Define Context types
98
type DevPresenceContextType = {
10-
lastSeen: Date | null;
11-
isConnected: boolean;
9+
isConnected: boolean | undefined;
1210
};
1311

1412
// Create Context with default values
1513
const DevPresenceContext = createContext<DevPresenceContextType>({
16-
lastSeen: null,
17-
isConnected: false,
14+
isConnected: undefined,
1815
});
1916

2017
// Provider component with enabled prop
@@ -30,50 +27,44 @@ export function DevPresenceProvider({ children, enabled = true }: DevPresencePro
3027

3128
// Only subscribe to event source if enabled is true
3229
const streamedEvents = useEventSource(
33-
`/resources/orgs/${organization.slug}/projects/${project.slug}/env/${environment.slug}/dev/presence`,
30+
`/resources/orgs/${organization.slug}/projects/${project.slug}/dev/presence`,
3431
{
3532
event: "presence",
3633
disabled: !enabled,
3734
}
3835
);
3936

40-
const [lastSeen, setLastSeen] = useState<Date | null>(null);
41-
42-
const debouncer = useDebounce((seen: Date | null) => {
43-
setLastSeen(seen);
44-
}, 3_000);
37+
const [isConnected, setIsConnected] = useState<boolean | undefined>(undefined);
4538

4639
useEffect(() => {
47-
// If disabled or no events, set lastSeen to null
40+
// If disabled or no events
4841
if (!enabled || streamedEvents === null) {
49-
debouncer(null);
42+
setIsConnected(undefined);
5043
return;
5144
}
5245

5346
try {
5447
const data = JSON.parse(streamedEvents) as any;
55-
if ("lastSeen" in data && data.lastSeen) {
48+
if ("isConnected" in data && data.isConnected) {
5649
try {
57-
const lastSeenDate = new Date(data.lastSeen);
58-
debouncer(lastSeenDate);
50+
setIsConnected(true);
5951
} catch (error) {
6052
console.log("DevPresence: Failed to parse lastSeen timestamp", { error });
61-
debouncer(null);
53+
setIsConnected(false);
6254
}
6355
} else {
64-
debouncer(null);
56+
setIsConnected(false);
6557
}
6658
} catch (error) {
6759
console.log("DevPresence: Failed to parse presence message", { error });
68-
debouncer(null);
60+
setIsConnected(false);
6961
}
7062
}, [streamedEvents, enabled]);
7163

7264
// Calculate isConnected and memoize the context value
7365
const contextValue = useMemo(() => {
74-
const isConnected = enabled && lastSeen !== null && lastSeen > new Date(Date.now() - 120_000);
75-
return { lastSeen, isConnected };
76-
}, [lastSeen, enabled]);
66+
return { isConnected };
67+
}, [isConnected, enabled]);
7768

7869
return <DevPresenceContext.Provider value={contextValue}>{children}</DevPresenceContext.Provider>;
7970
}

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ import {
2020
import { useNavigation } from "@remix-run/react";
2121
import { useEffect, useRef, useState, type ReactNode } from "react";
2222
import simplur from "simplur";
23-
import { ConnectedIcon, DisconnectedIcon } from "~/assets/icons/ConnectionIcons";
23+
import {
24+
CheckingConnectionIcon,
25+
ConnectedIcon,
26+
DisconnectedIcon,
27+
} from "~/assets/icons/ConnectionIcons";
2428
import { RunsIconExtraSmall, RunsIconSmall } from "~/assets/icons/RunsIcon";
2529
import { TaskIconSmall } from "~/assets/icons/TaskIcon";
2630
import { Avatar } from "~/components/primitives/Avatar";
@@ -82,6 +86,7 @@ import { SideMenuHeader } from "./SideMenuHeader";
8286
import { SideMenuItem } from "./SideMenuItem";
8387
import { SideMenuSection } from "./SideMenuSection";
8488
import { WaitpointTokenIcon } from "~/assets/icons/WaitpointTokenIcon";
89+
import { Spinner } from "../primitives/Spinner";
8590

8691
type SideMenuUser = Pick<User, "email" | "admin"> & { isImpersonating: boolean };
8792
export type SideMenuProject = Pick<
@@ -532,7 +537,9 @@ export function DevConnection() {
532537
variant="minimal/small"
533538
className="aspect-square h-7 p-1"
534539
LeadingIcon={
535-
isConnected ? (
540+
isConnected === undefined ? (
541+
<CheckingConnectionIcon className="size-5" />
542+
) : isConnected ? (
536543
<ConnectedIcon className="size-5" />
537544
) : (
538545
<DisconnectedIcon className="size-5" />
@@ -543,24 +550,34 @@ export function DevConnection() {
543550
</div>
544551
</TooltipTrigger>
545552
<TooltipContent side="right" className={"text-xs"}>
546-
{isConnected ? "Your dev server is connected" : "Your dev server is not connected"}
553+
{isConnected === undefined
554+
? "Checking connection..."
555+
: isConnected
556+
? "Your dev server is connected"
557+
: "Your dev server is not connected"}
547558
</TooltipContent>
548559
</Tooltip>
549560
</TooltipProvider>
550561
<DialogContent>
551562
<DialogHeader>
552-
{isConnected ? "Your dev server is connected" : "Your dev server is not connected"}
563+
{isConnected === undefined
564+
? "Checking connection..."
565+
: isConnected
566+
? "Your dev server is connected"
567+
: "Your dev server is not connected"}
553568
</DialogHeader>
554569
<div className="mt-2 flex flex-col gap-3 px-2">
555570
<div className="flex flex-col items-center justify-center gap-6 px-6 py-10">
556571
<img
557-
src={isConnected ? connectedImage : disconnectedImage}
558-
alt={isConnected ? "Connected" : "Disconnected"}
572+
src={isConnected === true ? connectedImage : disconnectedImage}
573+
alt={isConnected === true ? "Connected" : "Disconnected"}
559574
width={282}
560575
height={45}
561576
/>
562577
<Paragraph variant="small" className={isConnected ? "text-success" : "text-error"}>
563-
{isConnected
578+
{isConnected === undefined
579+
? "Checking connection..."
580+
: isConnected
564581
? "Your local dev server is connected to Trigger.dev"
565582
: "Your local dev server is not connected to Trigger.dev"}
566583
</Paragraph>

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ export function AppliedFilter({
3434
}: AppliedFilterProps) {
3535
const variantClassName = variants[variant];
3636
return (
37-
<div className={cn("flex items-center transition", variantClassName.box, className)}>
37+
<div
38+
className={cn(
39+
"flex items-center transition",
40+
variantClassName.box,
41+
!removable && "pr-2",
42+
className
43+
)}
44+
>
3845
<div className="flex items-center gap-0.5">
3946
<div className="text-text-dimmed">
4047
<span>{label}</span>:

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import { Button } from "./Buttons";
1010

1111
const variants = {
1212
small: {
13-
fieldStyles: "h-5 text-sm rounded-sm px-0.5",
13+
fieldStyles: "h-5 text-xs rounded-sm px-0.5",
1414
nowButtonVariant: "tertiary/small" as const,
1515
clearButtonVariant: "tertiary/small" as const,
1616
},
1717
medium: {
18-
fieldStyles: "h-7 text-base rounded px-1",
18+
fieldStyles: "h-7 text-sm rounded px-1",
1919
nowButtonVariant: "tertiary/medium" as const,
2020
clearButtonVariant: "minimal/medium" as const,
2121
},

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import * as Ariakit from "@ariakit/react";
2-
import { SelectProps as AriaSelectProps } from "@ariakit/react";
2+
import { type SelectProps as AriaSelectProps } from "@ariakit/react";
33
import { SelectValue } from "@ariakit/react-core/select/select-value";
44
import { Link } from "@remix-run/react";
55
import * as React from "react";
66
import { Fragment, useMemo, useState } from "react";
7-
import { ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
7+
import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
88
import { cn } from "~/utils/cn";
99
import { ShortcutKey } from "./ShortcutKey";
1010
import { ChevronDown } from "lucide-react";
11-
import { MatchSorterOptions, matchSorter } from "match-sorter";
11+
import { type MatchSorterOptions, matchSorter } from "match-sorter";
1212

1313
const sizes = {
1414
small: {

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@
33
import * as React from "react";
44
import * as SwitchPrimitives from "@radix-ui/react-switch";
55
import { cn } from "~/utils/cn";
6-
import { ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
6+
import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
7+
8+
const small = {
9+
container:
10+
"flex items-center h-[1.5rem] gap-x-1.5 rounded hover:bg-tertiary disabled:hover:bg-transparent pr-1 py-[0.1rem] pl-1.5 transition focus-custom disabled:hover:text-charcoal-400 disabled:opacity-50 text-charcoal-400 hover:text-charcoal-200 disabled:hover:cursor-not-allowed hover:cursor-pointer",
11+
root: "h-3 w-6",
12+
thumb: "size-2.5 data-[state=checked]:translate-x-2.5 data-[state=unchecked]:translate-x-0",
13+
text: "text-xs text-text-dimmed",
14+
};
715

816
const variations = {
917
large: {
@@ -12,12 +20,15 @@ const variations = {
1220
thumb: "size-5 data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
1321
text: "text-sm text-text-dimmed",
1422
},
15-
small: {
16-
container:
17-
"flex items-center h-[1.5rem] gap-x-1.5 rounded hover:bg-tertiary disabled:hover:bg-transparent pr-1 py-[0.1rem] pl-1.5 transition focus-custom disabled:hover:text-charcoal-400 disabled:opacity-50 text-charcoal-400 hover:text-charcoal-200 disabled:hover:cursor-not-allowed hover:cursor-pointer",
18-
root: "h-3 w-6",
19-
thumb: "size-2.5 data-[state=checked]:translate-x-2.5 data-[state=unchecked]:translate-x-0",
20-
text: "text-xs text-text-dimmed",
23+
small,
24+
"tertiary/small": {
25+
container: small.container,
26+
root: cn(
27+
small.root,
28+
"group-data-[state=unchecked]:bg-charcoal-600 group-data-[state=unchecked]:group-hover:bg-charcoal-500/50"
29+
),
30+
thumb: small.thumb,
31+
text: cn(small.text, "transition group-hover:text-text-bright"),
2132
},
2233
};
2334

apps/webapp/app/components/runs/v3/BatchFilters.tsx

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,7 @@ import {
3636
batchStatusTitle,
3737
descriptionForBatchStatus,
3838
} from "./BatchStatus";
39-
import {
40-
AppliedCustomDateRangeFilter,
41-
AppliedPeriodFilter,
42-
appliedSummary,
43-
CreatedAtDropdown,
44-
CustomDateRangeDropdown,
45-
FilterMenuProvider,
46-
} from "./SharedFilters";
39+
import { TimeFilter, appliedSummary, FilterMenuProvider } from "./SharedFilters";
4740

4841
export const BatchStatus = z.enum(allBatchStatuses);
4942

@@ -54,8 +47,8 @@ export const BatchListFilters = z.object({
5447
(value) => (typeof value === "string" ? [value] : value),
5548
BatchStatus.array().optional()
5649
),
57-
period: z.preprocess((value) => (value === "all" ? undefined : value), z.string().optional()),
5850
id: z.string().optional(),
51+
period: z.preprocess((value) => (value === "all" ? undefined : value), z.string().optional()),
5952
from: z.coerce.number().optional(),
6053
to: z.coerce.number().optional(),
6154
});
@@ -69,16 +62,12 @@ type BatchFiltersProps = {
6962
export function BatchFilters(props: BatchFiltersProps) {
7063
const location = useOptimisticLocation();
7164
const searchParams = new URLSearchParams(location.search);
72-
const hasFilters =
73-
searchParams.has("statuses") ||
74-
searchParams.has("id") ||
75-
searchParams.has("period") ||
76-
searchParams.has("from") ||
77-
searchParams.has("to");
65+
const hasFilters = searchParams.has("statuses") || searchParams.has("id");
7866

7967
return (
8068
<div className="flex flex-row flex-wrap items-center gap-1">
8169
<FilterMenu {...props} />
70+
<TimeFilter />
8271
<AppliedFilters />
8372
{hasFilters && (
8473
<Form className="h-6">
@@ -101,8 +90,6 @@ const filterTypes = [
10190
</div>
10291
),
10392
},
104-
{ name: "created", title: "Created", icon: <CalendarIcon className="size-4" /> },
105-
{ name: "daterange", title: "Custom date range", icon: <CalendarIcon className="size-4" /> },
10693
{ name: "batch", title: "Batch ID", icon: <Squares2X2Icon className="size-4" /> },
10794
] as const;
10895

@@ -148,8 +135,6 @@ function AppliedFilters() {
148135
return (
149136
<>
150137
<AppliedStatusFilter />
151-
<AppliedPeriodFilter />
152-
<AppliedCustomDateRangeFilter />
153138
<AppliedBatchIdFilter />
154139
</>
155140
);
@@ -169,10 +154,6 @@ function Menu(props: MenuProps) {
169154
return <MainMenu {...props} />;
170155
case "statuses":
171156
return <StatusDropdown onClose={() => props.setFilterType(undefined)} {...props} />;
172-
case "created":
173-
return <CreatedAtDropdown onClose={() => props.setFilterType(undefined)} {...props} />;
174-
case "daterange":
175-
return <CustomDateRangeDropdown onClose={() => props.setFilterType(undefined)} {...props} />;
176157
case "batch":
177158
return <BatchIdDropdown onClose={() => props.setFilterType(undefined)} {...props} />;
178159
}
@@ -181,7 +162,6 @@ function Menu(props: MenuProps) {
181162
function MainMenu({ searchValue, trigger, clearSearchValue, setFilterType }: MenuProps) {
182163
const filtered = useMemo(() => {
183164
return filterTypes.filter((item) => {
184-
if (item.name === "daterange") return false;
185165
return item.title.toLowerCase().includes(searchValue.toLowerCase());
186166
});
187167
}, [searchValue]);

0 commit comments

Comments
 (0)