-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add basic dashboard for workflows with mocks * fix: switch not animating thumb * more shadcn components * better my workflow page * fix: fix some type problems.
- Loading branch information
1 parent
d073cd8
commit 3f46f10
Showing
29 changed files
with
2,175 additions
and
14 deletions.
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
packages/client/app/components/workflows/explore-filters.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { Search } from "lucide-react"; | ||
import { Input } from "@data-river/shared/ui/components/ui/input"; | ||
import { | ||
Select, | ||
SelectContent, | ||
SelectItem, | ||
SelectTrigger, | ||
SelectValue, | ||
} from "@data-river/shared/ui/components/ui/select"; | ||
|
||
export function ExploreFilters() { | ||
return ( | ||
<div className="flex gap-4"> | ||
<div className="relative w-64"> | ||
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" /> | ||
<Input | ||
placeholder="Search public workflows..." | ||
className="pl-8" | ||
// TODO: Add search functionality | ||
/> | ||
</div> | ||
<Select defaultValue="popular"> | ||
<SelectTrigger className="w-[180px]"> | ||
<SelectValue placeholder="Sort by" /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
<SelectItem value="popular">Most Popular</SelectItem> | ||
<SelectItem value="recent">Recently Added</SelectItem> | ||
<SelectItem value="runs">Most Runs</SelectItem> | ||
<SelectItem value="remixes">Most Remixes</SelectItem> | ||
</SelectContent> | ||
</Select> | ||
</div> | ||
); | ||
} |
41 changes: 41 additions & 0 deletions
41
packages/client/app/components/workflows/filter-sections/filter-section.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { useState } from "react"; | ||
import { ChevronDown } from "lucide-react"; | ||
import { | ||
Collapsible, | ||
CollapsibleContent, | ||
CollapsibleTrigger, | ||
} from "@data-river/shared/ui/components/ui/collapsible"; | ||
import { cn } from "@data-river/shared/ui/utils"; | ||
|
||
interface FilterSectionProps { | ||
title: string; | ||
defaultOpen?: boolean; | ||
children: React.ReactNode; | ||
} | ||
|
||
export function FilterSection({ | ||
title, | ||
defaultOpen = false, | ||
children, | ||
}: FilterSectionProps) { | ||
const [isOpen, setIsOpen] = useState(defaultOpen); | ||
|
||
return ( | ||
<div className="border-b border-border/50 last:border-none"> | ||
<Collapsible open={isOpen} onOpenChange={setIsOpen}> | ||
<CollapsibleTrigger className="flex w-full items-center justify-between py-4 text-sm font-medium"> | ||
{title} | ||
<ChevronDown | ||
className={cn( | ||
"h-4 w-4 text-muted-foreground transition-transform", | ||
{ | ||
"transform rotate-180": isOpen, | ||
}, | ||
)} | ||
/> | ||
</CollapsibleTrigger> | ||
<CollapsibleContent className="pb-4">{children}</CollapsibleContent> | ||
</Collapsible> | ||
</div> | ||
); | ||
} |
36 changes: 36 additions & 0 deletions
36
packages/client/app/components/workflows/filter-sections/range-filter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { FilterSection } from "./filter-section"; | ||
import { Slider } from "@data-river/shared/ui/components/ui/slider"; | ||
|
||
interface RangeFilterProps { | ||
title: string; | ||
value: [number, number]; | ||
onChange: (value: [number, number]) => void; | ||
max: number; | ||
step: number; | ||
} | ||
|
||
export function RangeFilter({ | ||
title, | ||
value, | ||
onChange, | ||
max, | ||
step, | ||
}: RangeFilterProps) { | ||
return ( | ||
<FilterSection title={title}> | ||
<div className="space-y-4"> | ||
<Slider | ||
value={value} | ||
onValueChange={(value) => onChange(value as [number, number])} | ||
max={max} | ||
step={step} | ||
className="mt-2" | ||
/> | ||
<div className="flex justify-between text-xs text-muted-foreground"> | ||
<span>{value[0]}</span> | ||
<span>{value[1]}</span> | ||
</div> | ||
</div> | ||
</FilterSection> | ||
); | ||
} |
23 changes: 23 additions & 0 deletions
23
packages/client/app/components/workflows/filter-sections/status-filter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Switch } from "@data-river/shared/ui/components/ui/switch"; | ||
import { Label } from "@data-river/shared/ui/components/ui/label"; | ||
import { FilterSection } from "./filter-section"; | ||
|
||
interface StatusFilterProps { | ||
isPublic: boolean; | ||
onChange: (isPublic: boolean) => void; | ||
} | ||
|
||
export function StatusFilter({ isPublic, onChange }: StatusFilterProps) { | ||
return ( | ||
<FilterSection title="Status" defaultOpen> | ||
<div className="space-y-3"> | ||
<div className="flex items-center justify-between"> | ||
<Label htmlFor="public" className="text-sm"> | ||
Public | ||
</Label> | ||
<Switch id="public" checked={isPublic} onCheckedChange={onChange} /> | ||
</div> | ||
</div> | ||
</FilterSection> | ||
); | ||
} |
47 changes: 47 additions & 0 deletions
47
packages/client/app/components/workflows/filter-sections/tags-filter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { FilterSection } from "./filter-section"; | ||
import { cn } from "@data-river/shared/ui/utils"; | ||
|
||
const AVAILABLE_TAGS = [ | ||
{ id: "automation", count: 9 }, | ||
{ id: "api", count: 5 }, | ||
{ id: "data-processing", count: 5 }, | ||
{ id: "integration", count: 8 }, | ||
{ id: "ai", count: 3 }, | ||
{ id: "backup", count: 9 }, | ||
{ id: "notifications", count: 8 }, | ||
] as const; | ||
|
||
interface TagsFilterProps { | ||
selectedTags: string[]; | ||
onChange: (tags: string[]) => void; | ||
} | ||
|
||
export function TagsFilter({ selectedTags, onChange }: TagsFilterProps) { | ||
const toggleTag = (tag: string) => { | ||
const newTags = selectedTags.includes(tag) | ||
? selectedTags.filter((t) => t !== tag) | ||
: [...selectedTags, tag]; | ||
onChange(newTags); | ||
}; | ||
|
||
return ( | ||
<FilterSection title="Tags" defaultOpen> | ||
<div className="space-y-1"> | ||
{AVAILABLE_TAGS.map(({ id, count }) => ( | ||
<div | ||
key={id} | ||
className={cn( | ||
"flex items-center gap-2 px-2 py-1.5 text-sm rounded-md cursor-pointer hover:bg-muted transition-colors", | ||
selectedTags.includes(id) && "bg-muted", | ||
)} | ||
onClick={() => toggleTag(id)} | ||
> | ||
<div className="h-2 w-2 rounded-full bg-primary/60" /> | ||
<span className="flex-1">{id}</span> | ||
<span className="text-xs text-muted-foreground">{count}</span> | ||
</div> | ||
))} | ||
</div> | ||
</FilterSection> | ||
); | ||
} |
121 changes: 121 additions & 0 deletions
121
packages/client/app/components/workflows/filter-sections/time-range-filter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { useState } from "react"; | ||
import { Calendar } from "@data-river/shared/ui/components/ui/calendar"; | ||
import { format, subDays, startOfToday } from "date-fns"; | ||
import { CalendarIcon } from "lucide-react"; | ||
import { | ||
Popover, | ||
PopoverContent, | ||
PopoverTrigger, | ||
} from "@data-river/shared/ui/components/ui/popover"; | ||
import { Button } from "@data-river/shared/ui/components/ui/button"; | ||
import { cn } from "@data-river/shared/ui/utils"; | ||
import { FilterSection } from "./filter-section"; | ||
|
||
const TIME_RANGES = [ | ||
{ label: "Today", value: "today", shortcut: "T" }, | ||
{ label: "Yesterday", value: "yesterday", shortcut: "Y" }, | ||
{ label: "Last hour", value: "hour", shortcut: "H" }, | ||
{ label: "Last 7 days", value: "7days", shortcut: "W" }, | ||
{ label: "Last 14 days", value: "14days", shortcut: "B" }, | ||
{ label: "Last 30 days", value: "30days", shortcut: "M" }, | ||
] as const; | ||
|
||
function getPresetRange(preset: (typeof TIME_RANGES)[number]["value"]) { | ||
const today = startOfToday(); | ||
|
||
switch (preset) { | ||
case "today": | ||
return { from: today, to: new Date() }; | ||
case "yesterday": | ||
return { from: subDays(today, 1), to: today }; | ||
case "hour": | ||
return { from: subDays(new Date(), 1 / 24), to: new Date() }; | ||
case "7days": | ||
return { from: subDays(today, 7), to: new Date() }; | ||
case "14days": | ||
return { from: subDays(today, 14), to: new Date() }; | ||
case "30days": | ||
return { from: subDays(today, 30), to: new Date() }; | ||
default: | ||
return null; | ||
} | ||
} | ||
|
||
interface TimeRangeFilterProps { | ||
dateRange: { from?: Date; to?: Date } | null; | ||
onChange: (range: { from?: Date; to?: Date } | null) => void; | ||
} | ||
|
||
export function TimeRangeFilter({ dateRange, onChange }: TimeRangeFilterProps) { | ||
const [open, setOpen] = useState(false); | ||
|
||
return ( | ||
<FilterSection title="Time Range"> | ||
<Popover open={open} onOpenChange={setOpen}> | ||
<PopoverTrigger asChild> | ||
<Button | ||
variant="outline" | ||
className={cn( | ||
"w-full justify-start text-left font-normal", | ||
!dateRange && "text-muted-foreground", | ||
)} | ||
> | ||
<CalendarIcon className="mr-2 h-4 w-4" /> | ||
{dateRange?.from | ||
? `${format(dateRange.from, "LLL dd, y")} - ${ | ||
dateRange.to ? format(dateRange.to, "LLL dd, y") : "..." | ||
}` | ||
: "Pick a date range"} | ||
</Button> | ||
</PopoverTrigger> | ||
<PopoverContent className="w-full p-0" align="start"> | ||
<div className="flex"> | ||
<div className="w-[200px] border-r p-4 space-y-4"> | ||
<div className="font-medium text-sm">Quick Select</div> | ||
{TIME_RANGES.map(({ label, value, shortcut }) => ( | ||
<div | ||
key={value} | ||
className={cn( | ||
"flex items-center gap-3 text-sm cursor-pointer hover:text-primary transition-colors py-1", | ||
dateRange === getPresetRange(value) && "text-primary", | ||
)} | ||
onClick={() => { | ||
onChange(getPresetRange(value)); | ||
setOpen(false); | ||
}} | ||
> | ||
<kbd className="pointer-events-none inline-flex h-6 select-none items-center gap-1 rounded border bg-muted px-2 font-mono text-[10px] font-medium text-muted-foreground"> | ||
{shortcut} | ||
</kbd> | ||
<span className="font-medium">{label}</span> | ||
</div> | ||
))} | ||
</div> | ||
<div className="p-4 flex flex-col"> | ||
<div className="font-medium text-sm mb-4">Custom Range</div> | ||
<Calendar | ||
mode="range" | ||
// selected={{ | ||
// from: dateRange?.from || undefined, | ||
// to: dateRange?.to || undefined, | ||
// }} | ||
// onSelect={(range) => { | ||
// onChange( | ||
// range?.from | ||
// ? { | ||
// from: range.from, | ||
// to: range.to || range.from, | ||
// } | ||
// : null, | ||
// ); | ||
// if (range?.to) setOpen(false); | ||
// }} | ||
numberOfMonths={1} | ||
/> | ||
</div> | ||
</div> | ||
</PopoverContent> | ||
</Popover> | ||
</FilterSection> | ||
); | ||
} |
Oops, something went wrong.