Skip to content

Commit 39a332e

Browse files
authored
feat: add filter for active jobs in the dashboard (#601)
* feat: add filter for active jobs in the dashboard * use cursor-pointer when hovering Switch label * remove unused import * remove unnecessary span * add flex-gap
1 parent 498f56d commit 39a332e

File tree

5 files changed

+60
-9
lines changed

5 files changed

+60
-9
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const variations = {
1515
container: "flex items-center gap-x-1.5 rounded hover:bg-slate-850 pr-1 py-[0.1rem] pl-1.5",
1616
root: "h-3 w-6",
1717
thumb: "h-2.5 w-2.5 data-[state=checked]:translate-x-2.5 data-[state=unchecked]:translate-x-0",
18-
text: "text-xs text-slate-400 group-hover:text-slate-200 mt-0.5",
18+
text: "text-xs text-slate-400 group-hover:text-slate-200 hover:cursor-pointer",
1919
},
2020
};
2121

apps/webapp/app/hooks/useFilterJobs.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
import { ProjectJob } from "./useJobs";
22
import { useTextFilter } from "./useTextFilter";
3+
import { useToggleFilter } from "./useToggleFilter";
34

4-
export function useFilterJobs(jobs: ProjectJob[]) {
5-
const { filterText, setFilterText, filteredItems } = useTextFilter<ProjectJob>({
5+
export function useFilterJobs(jobs: ProjectJob[], onlyActiveJobs = false) {
6+
const toggleFilterRes = useToggleFilter<ProjectJob>({
67
items: jobs,
8+
filter: (job, onlyActiveJobs) => {
9+
if (onlyActiveJobs && job.status !== "ACTIVE") {
10+
return false;
11+
}
12+
return true;
13+
},
14+
defaultValue: onlyActiveJobs,
15+
});
16+
17+
const textFilterRes = useTextFilter<ProjectJob>({
18+
items: toggleFilterRes.filteredItems,
719
filter: (job, text) => {
820
if (job.slug.toLowerCase().includes(text.toLowerCase())) return true;
921
if (job.title.toLowerCase().includes(text.toLowerCase())) return true;
@@ -24,5 +36,11 @@ export function useFilterJobs(jobs: ProjectJob[]) {
2436
},
2537
});
2638

27-
return { filterText, setFilterText, filteredItems };
39+
return {
40+
filteredItems: textFilterRes.filteredItems,
41+
filterText: textFilterRes.filterText,
42+
setFilterText: textFilterRes.setFilterText,
43+
onlyActiveJobs: toggleFilterRes.isToggleActive,
44+
setOnlyActiveJobs: toggleFilterRes.setToggleActive,
45+
};
2846
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useMemo, useState } from "react";
2+
3+
type ToggleFilterProps<T> = {
4+
items: T[];
5+
filter: (item: T, isToggleActive: boolean) => boolean;
6+
defaultValue?: boolean;
7+
};
8+
9+
export function useToggleFilter<T>({ items, filter, defaultValue = false }: ToggleFilterProps<T>) {
10+
const [isToggleActive, setToggleActive] = useState(defaultValue);
11+
12+
const filteredItems = useMemo<T[]>(() => {
13+
return items.filter((item) => filter(item, isToggleActive));
14+
}, [items, isToggleActive]);
15+
16+
return {
17+
isToggleActive,
18+
setToggleActive,
19+
filteredItems,
20+
};
21+
}

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam._index/route.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
PageTitleRow,
2020
} from "~/components/primitives/PageHeader";
2121
import { Paragraph } from "~/components/primitives/Paragraph";
22+
import { Switch } from "~/components/primitives/Switch";
2223
import { TextLink } from "~/components/primitives/TextLink";
2324
import { useFilterJobs } from "~/hooks/useFilterJobs";
2425
import { useOrganization } from "~/hooks/useOrganizations";
@@ -62,8 +63,11 @@ export default function Page() {
6263
const organization = useOrganization();
6364
const project = useProject();
6465
const { jobs } = useTypedLoaderData<typeof loader>();
65-
const { filterText, setFilterText, filteredItems } = useFilterJobs(jobs);
66-
const hasJobs = jobs.length > 0;
66+
const { filterText, setFilterText, filteredItems, onlyActiveJobs, setOnlyActiveJobs } =
67+
useFilterJobs(jobs);
68+
const totalJobs = jobs.length;
69+
const hasJobs = totalJobs > 0;
70+
const activeJobCount = jobs.filter((j) => j.status === "ACTIVE").length;
6771

6872
return (
6973
<PageContainer className={hasJobs ? "" : "grid-rows-1"}>
@@ -74,7 +78,8 @@ export default function Page() {
7478
</PageTitleRow>
7579
<PageInfoRow>
7680
<PageInfoGroup>
77-
<PageInfoProperty icon={"job"} label={"Active Jobs"} value={jobs.length} />
81+
<PageInfoProperty icon={"job"} label={"All Jobs"} value={totalJobs} />
82+
<PageInfoProperty icon={"job"} label={"Active Jobs"} value={activeJobCount} />
7883
</PageInfoGroup>
7984
</PageInfoRow>
8085
</PageHeader>
@@ -96,7 +101,7 @@ export default function Page() {
96101
</Callout>
97102
)}
98103
<div className="mb-2 flex flex-col">
99-
<div className="flex w-full">
104+
<div className="flex w-full gap-x-2">
100105
<Input
101106
placeholder="Search Jobs"
102107
variant="tertiary"
@@ -106,6 +111,13 @@ export default function Page() {
106111
onChange={(e) => setFilterText(e.target.value)}
107112
autoFocus
108113
/>
114+
<Switch
115+
variant="small"
116+
label="Active Jobs"
117+
checked={onlyActiveJobs}
118+
onCheckedChange={setOnlyActiveJobs}
119+
className={"shrink-0"}
120+
/>
109121
<HelpTrigger title="Example Jobs and inspiration" />
110122
</div>
111123
</div>

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ function PossibleIntegrationsList({
152152
onCheckedChange={setOnlyShowIntegrations}
153153
variant="small"
154154
label={
155-
<span className="inline-flex items-center gap-1">
155+
<span className="mt-0.5 inline-flex items-center gap-1">
156156
<IntegrationIcon /> Trigger.dev Integrations
157157
</span>
158158
}

0 commit comments

Comments
 (0)