-
-
Notifications
You must be signed in to change notification settings - Fork 181
fix(ui): resolve Issue #428 & #429 - filter dropdown and pagination bugs #436
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,16 +1,25 @@ | ||||||||||||||||||||||||||||||||||||||||||
| "use client"; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import { addDays, format, parse } from "date-fns"; | ||||||||||||||||||||||||||||||||||||||||||
| import { Download } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||||
| import { Check, ChevronsUpDown, Download } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||||
| import { useTranslations } from "next-intl"; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import { useCallback, useEffect, useMemo, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||
| import { toast } from "sonner"; | ||||||||||||||||||||||||||||||||||||||||||
| import { getKeys } from "@/actions/keys"; | ||||||||||||||||||||||||||||||||||||||||||
| import { exportUsageLogs } from "@/actions/usage-logs"; | ||||||||||||||||||||||||||||||||||||||||||
| import { Button } from "@/components/ui/button"; | ||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||
| Command, | ||||||||||||||||||||||||||||||||||||||||||
| CommandEmpty, | ||||||||||||||||||||||||||||||||||||||||||
| CommandGroup, | ||||||||||||||||||||||||||||||||||||||||||
| CommandInput, | ||||||||||||||||||||||||||||||||||||||||||
| CommandItem, | ||||||||||||||||||||||||||||||||||||||||||
| CommandList, | ||||||||||||||||||||||||||||||||||||||||||
| } from "@/components/ui/command"; | ||||||||||||||||||||||||||||||||||||||||||
| import { Input } from "@/components/ui/input"; | ||||||||||||||||||||||||||||||||||||||||||
| import { Label } from "@/components/ui/label"; | ||||||||||||||||||||||||||||||||||||||||||
| import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; | ||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||
| Select, | ||||||||||||||||||||||||||||||||||||||||||
| SelectContent, | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -99,6 +108,8 @@ export function UsageLogsFilters({ | |||||||||||||||||||||||||||||||||||||||||
| const [keys, setKeys] = useState<Key[]>(initialKeys); | ||||||||||||||||||||||||||||||||||||||||||
| const [localFilters, setLocalFilters] = useState(filters); | ||||||||||||||||||||||||||||||||||||||||||
| const [isExporting, setIsExporting] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||
| const [userPopoverOpen, setUserPopoverOpen] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||
| const [providerPopoverOpen, setProviderPopoverOpen] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||
| if (initialKeys.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -263,26 +274,72 @@ export function UsageLogsFilters({ | |||||||||||||||||||||||||||||||||||||||||
| {isAdmin && ( | ||||||||||||||||||||||||||||||||||||||||||
| <div className="space-y-2 lg:col-span-4"> | ||||||||||||||||||||||||||||||||||||||||||
| <Label>{t("logs.filters.user")}</Label> | ||||||||||||||||||||||||||||||||||||||||||
| <Select | ||||||||||||||||||||||||||||||||||||||||||
| value={localFilters.userId?.toString() || ""} | ||||||||||||||||||||||||||||||||||||||||||
| onValueChange={handleUserChange} | ||||||||||||||||||||||||||||||||||||||||||
| disabled={isUsersLoading} | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <SelectTrigger> | ||||||||||||||||||||||||||||||||||||||||||
| <SelectValue | ||||||||||||||||||||||||||||||||||||||||||
| placeholder={ | ||||||||||||||||||||||||||||||||||||||||||
| isUsersLoading ? t("logs.stats.loading") : t("logs.filters.allUsers") | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||
| </SelectTrigger> | ||||||||||||||||||||||||||||||||||||||||||
| <SelectContent> | ||||||||||||||||||||||||||||||||||||||||||
| {users.map((user) => ( | ||||||||||||||||||||||||||||||||||||||||||
| <SelectItem key={user.id} value={user.id.toString()}> | ||||||||||||||||||||||||||||||||||||||||||
| {user.name} | ||||||||||||||||||||||||||||||||||||||||||
| </SelectItem> | ||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||
| </SelectContent> | ||||||||||||||||||||||||||||||||||||||||||
| </Select> | ||||||||||||||||||||||||||||||||||||||||||
| <Popover open={userPopoverOpen} onOpenChange={setUserPopoverOpen}> | ||||||||||||||||||||||||||||||||||||||||||
| <PopoverTrigger asChild> | ||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||
| variant="outline" | ||||||||||||||||||||||||||||||||||||||||||
| role="combobox" | ||||||||||||||||||||||||||||||||||||||||||
| aria-expanded={userPopoverOpen} | ||||||||||||||||||||||||||||||||||||||||||
| disabled={isUsersLoading} | ||||||||||||||||||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||||||||||||||||||
| className="w-full justify-between" | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| {localFilters.userId ? ( | ||||||||||||||||||||||||||||||||||||||||||
| (users.find((user) => user.id === localFilters.userId)?.name ?? | ||||||||||||||||||||||||||||||||||||||||||
| localFilters.userId.toString()) | ||||||||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||||||||
| <span className="text-muted-foreground"> | ||||||||||||||||||||||||||||||||||||||||||
| {isUsersLoading ? t("logs.stats.loading") : t("logs.filters.allUsers")} | ||||||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||
| <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> | ||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||
| </PopoverTrigger> | ||||||||||||||||||||||||||||||||||||||||||
| <PopoverContent | ||||||||||||||||||||||||||||||||||||||||||
| className="w-[320px] p-0" | ||||||||||||||||||||||||||||||||||||||||||
| align="start" | ||||||||||||||||||||||||||||||||||||||||||
| onWheel={(e) => e.stopPropagation()} | ||||||||||||||||||||||||||||||||||||||||||
| onTouchMove={(e) => e.stopPropagation()} | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <Command shouldFilter={true}> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandInput placeholder={t("logs.filters.searchUser")} /> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandList className="max-h-[250px] overflow-y-auto"> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandEmpty> | ||||||||||||||||||||||||||||||||||||||||||
| {isUsersLoading ? t("logs.stats.loading") : t("logs.filters.noUserFound")} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandEmpty> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandGroup> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandItem | ||||||||||||||||||||||||||||||||||||||||||
| value={t("logs.filters.allUsers")} | ||||||||||||||||||||||||||||||||||||||||||
| onSelect={() => { | ||||||||||||||||||||||||||||||||||||||||||
| void handleUserChange(""); | ||||||||||||||||||||||||||||||||||||||||||
| setUserPopoverOpen(false); | ||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||
| className="cursor-pointer" | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <span className="flex-1">{t("logs.filters.allUsers")}</span> | ||||||||||||||||||||||||||||||||||||||||||
| {!localFilters.userId && <Check className="h-4 w-4 text-primary" />} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandItem> | ||||||||||||||||||||||||||||||||||||||||||
| {users.map((user) => ( | ||||||||||||||||||||||||||||||||||||||||||
| <CommandItem | ||||||||||||||||||||||||||||||||||||||||||
| key={user.id} | ||||||||||||||||||||||||||||||||||||||||||
| value={user.name} | ||||||||||||||||||||||||||||||||||||||||||
| onSelect={() => { | ||||||||||||||||||||||||||||||||||||||||||
| void handleUserChange(user.id.toString()); | ||||||||||||||||||||||||||||||||||||||||||
| setUserPopoverOpen(false); | ||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||
| className="cursor-pointer" | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <span className="flex-1">{user.name}</span> | ||||||||||||||||||||||||||||||||||||||||||
| {localFilters.userId === user.id && ( | ||||||||||||||||||||||||||||||||||||||||||
| <Check className="h-4 w-4 text-primary" /> | ||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandItem> | ||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandGroup> | ||||||||||||||||||||||||||||||||||||||||||
| </CommandList> | ||||||||||||||||||||||||||||||||||||||||||
| </Command> | ||||||||||||||||||||||||||||||||||||||||||
| </PopoverContent> | ||||||||||||||||||||||||||||||||||||||||||
| </Popover> | ||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -324,31 +381,82 @@ export function UsageLogsFilters({ | |||||||||||||||||||||||||||||||||||||||||
| {isAdmin && ( | ||||||||||||||||||||||||||||||||||||||||||
| <div className="space-y-2 lg:col-span-4"> | ||||||||||||||||||||||||||||||||||||||||||
| <Label>{t("logs.filters.provider")}</Label> | ||||||||||||||||||||||||||||||||||||||||||
| <Select | ||||||||||||||||||||||||||||||||||||||||||
| value={localFilters.providerId?.toString() || ""} | ||||||||||||||||||||||||||||||||||||||||||
| onValueChange={(value: string) => | ||||||||||||||||||||||||||||||||||||||||||
| setLocalFilters({ | ||||||||||||||||||||||||||||||||||||||||||
| ...localFilters, | ||||||||||||||||||||||||||||||||||||||||||
| providerId: value ? parseInt(value, 10) : undefined, | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| disabled={isProvidersLoading} | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <SelectTrigger> | ||||||||||||||||||||||||||||||||||||||||||
| <SelectValue | ||||||||||||||||||||||||||||||||||||||||||
| placeholder={ | ||||||||||||||||||||||||||||||||||||||||||
| isProvidersLoading ? t("logs.stats.loading") : t("logs.filters.allProviders") | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||
| </SelectTrigger> | ||||||||||||||||||||||||||||||||||||||||||
| <SelectContent> | ||||||||||||||||||||||||||||||||||||||||||
| {providers.map((provider) => ( | ||||||||||||||||||||||||||||||||||||||||||
| <SelectItem key={provider.id} value={provider.id.toString()}> | ||||||||||||||||||||||||||||||||||||||||||
| {provider.name} | ||||||||||||||||||||||||||||||||||||||||||
| </SelectItem> | ||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||
| </SelectContent> | ||||||||||||||||||||||||||||||||||||||||||
| </Select> | ||||||||||||||||||||||||||||||||||||||||||
| <Popover open={providerPopoverOpen} onOpenChange={setProviderPopoverOpen}> | ||||||||||||||||||||||||||||||||||||||||||
| <PopoverTrigger asChild> | ||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||
| variant="outline" | ||||||||||||||||||||||||||||||||||||||||||
| role="combobox" | ||||||||||||||||||||||||||||||||||||||||||
| aria-expanded={providerPopoverOpen} | ||||||||||||||||||||||||||||||||||||||||||
| disabled={isProvidersLoading} | ||||||||||||||||||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||||||||||||||||||
| className="w-full justify-between" | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| {localFilters.providerId ? ( | ||||||||||||||||||||||||||||||||||||||||||
| (providers.find((provider) => provider.id === localFilters.providerId)?.name ?? | ||||||||||||||||||||||||||||||||||||||||||
| localFilters.providerId.toString()) | ||||||||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||||||||
| <span className="text-muted-foreground"> | ||||||||||||||||||||||||||||||||||||||||||
| {isProvidersLoading | ||||||||||||||||||||||||||||||||||||||||||
| ? t("logs.stats.loading") | ||||||||||||||||||||||||||||||||||||||||||
| : t("logs.filters.allProviders")} | ||||||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+394
to
+403
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the user filter, Add this to your component: const providerMap = useMemo(() => new Map(providers.map((provider) => [provider.id, provider.name])), [providers]);
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
| <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> | ||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||
| </PopoverTrigger> | ||||||||||||||||||||||||||||||||||||||||||
| <PopoverContent | ||||||||||||||||||||||||||||||||||||||||||
| className="w-[320px] p-0" | ||||||||||||||||||||||||||||||||||||||||||
| align="start" | ||||||||||||||||||||||||||||||||||||||||||
| onWheel={(e) => e.stopPropagation()} | ||||||||||||||||||||||||||||||||||||||||||
| onTouchMove={(e) => e.stopPropagation()} | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <Command shouldFilter={true}> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandInput placeholder={t("logs.filters.searchProvider")} /> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandList className="max-h-[250px] overflow-y-auto"> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandEmpty> | ||||||||||||||||||||||||||||||||||||||||||
| {isProvidersLoading | ||||||||||||||||||||||||||||||||||||||||||
| ? t("logs.stats.loading") | ||||||||||||||||||||||||||||||||||||||||||
| : t("logs.filters.noProviderFound")} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandEmpty> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandGroup> | ||||||||||||||||||||||||||||||||||||||||||
| <CommandItem | ||||||||||||||||||||||||||||||||||||||||||
| value={t("logs.filters.allProviders")} | ||||||||||||||||||||||||||||||||||||||||||
| onSelect={() => { | ||||||||||||||||||||||||||||||||||||||||||
| setLocalFilters({ | ||||||||||||||||||||||||||||||||||||||||||
| ...localFilters, | ||||||||||||||||||||||||||||||||||||||||||
| providerId: undefined, | ||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||
| setProviderPopoverOpen(false); | ||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||
| className="cursor-pointer" | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <span className="flex-1">{t("logs.filters.allProviders")}</span> | ||||||||||||||||||||||||||||||||||||||||||
| {!localFilters.providerId && <Check className="h-4 w-4 text-primary" />} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandItem> | ||||||||||||||||||||||||||||||||||||||||||
| {providers.map((provider) => ( | ||||||||||||||||||||||||||||||||||||||||||
| <CommandItem | ||||||||||||||||||||||||||||||||||||||||||
| key={provider.id} | ||||||||||||||||||||||||||||||||||||||||||
| value={provider.name} | ||||||||||||||||||||||||||||||||||||||||||
| onSelect={() => { | ||||||||||||||||||||||||||||||||||||||||||
| setLocalFilters({ | ||||||||||||||||||||||||||||||||||||||||||
| ...localFilters, | ||||||||||||||||||||||||||||||||||||||||||
| providerId: provider.id, | ||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||
| setProviderPopoverOpen(false); | ||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||
| className="cursor-pointer" | ||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||
| <span className="flex-1">{provider.name}</span> | ||||||||||||||||||||||||||||||||||||||||||
| {localFilters.providerId === provider.id && ( | ||||||||||||||||||||||||||||||||||||||||||
| <Check className="h-4 w-4 text-primary" /> | ||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandItem> | ||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||
| </CommandGroup> | ||||||||||||||||||||||||||||||||||||||||||
| </CommandList> | ||||||||||||||||||||||||||||||||||||||||||
| </Command> | ||||||||||||||||||||||||||||||||||||||||||
| </PopoverContent> | ||||||||||||||||||||||||||||||||||||||||||
| </Popover> | ||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -172,9 +172,8 @@ export async function findUsageLogsBatch( | |
| // Cursor-based pagination: WHERE (created_at, id) < (cursor_created_at, cursor_id) | ||
| // Using row value comparison for efficient keyset pagination | ||
| if (cursor) { | ||
| const cursorDate = new Date(cursor.createdAt); | ||
| conditions.push( | ||
| sql`(${messageRequest.createdAt}, ${messageRequest.id}) < (${cursorDate.toISOString()}::timestamptz, ${cursor.id})` | ||
| sql`(${messageRequest.createdAt}, ${messageRequest.id}) < (${cursor.createdAt}::timestamptz, ${cursor.id})` | ||
| ); | ||
| } | ||
|
|
||
|
|
@@ -185,6 +184,7 @@ export async function findUsageLogsBatch( | |
| .select({ | ||
| id: messageRequest.id, | ||
| createdAt: messageRequest.createdAt, | ||
| createdAtRaw: sql<string>`to_char(${messageRequest.createdAt}, 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"')`, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [CRITICAL] [LOGIC-BUG] Evidence ( Why this is a problem: Suggested fix: createdAtRaw: sql<string>`
to_char(
${messageRequest.createdAt} AT TIME ZONE 'UTC',
'YYYY-MM-DD"T"HH24:MI:SS.US"Z"'
)
`, |
||
| sessionId: messageRequest.sessionId, | ||
| requestSequence: messageRequest.requestSequence, | ||
| userName: users.name, | ||
|
|
@@ -228,9 +228,7 @@ export async function findUsageLogsBatch( | |
| // Calculate next cursor from the last record | ||
| const lastLog = logsToReturn[logsToReturn.length - 1]; | ||
| const nextCursor = | ||
| hasMore && lastLog?.createdAt | ||
| ? { createdAt: lastLog.createdAt.toISOString(), id: lastLog.id } | ||
| : null; | ||
| hasMore && lastLog?.createdAtRaw ? { createdAt: lastLog.createdAtRaw, id: lastLog.id } : null; | ||
|
|
||
| const logs: UsageLogRow[] = logsToReturn.map((row) => { | ||
| const totalRowTokens = | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -167,9 +167,8 @@ export async function findUserListBatch( | |
|
|
||
| // Cursor-based pagination: WHERE (created_at, id) > (cursor_created_at, cursor_id) | ||
| if (cursor) { | ||
| const cursorDate = new Date(cursor.createdAt); | ||
| conditions.push( | ||
| sql`(${users.createdAt}, ${users.id}) > (${cursorDate.toISOString()}::timestamptz, ${cursor.id})` | ||
| sql`(${users.createdAt}, ${users.id}) > (${cursor.createdAt}::timestamptz, ${cursor.id})` | ||
| ); | ||
| } | ||
|
|
||
|
|
@@ -187,6 +186,7 @@ export async function findUserListBatch( | |
| providerGroup: users.providerGroup, | ||
| tags: users.tags, | ||
| createdAt: users.createdAt, | ||
| createdAtRaw: sql<string>`to_char(${users.createdAt}, 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"')`, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [CRITICAL] [LOGIC-BUG] Evidence ( Why this is a problem: Suggested fix: createdAtRaw: sql<string>`
to_char(${users.createdAt} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"')
`, |
||
| updatedAt: users.updatedAt, | ||
| deletedAt: users.deletedAt, | ||
| limit5hUsd: users.limit5hUsd, | ||
|
|
@@ -211,8 +211,8 @@ export async function findUserListBatch( | |
|
|
||
| const lastUser = usersToReturn[usersToReturn.length - 1]; | ||
| const nextCursor = | ||
| hasMore && lastUser?.createdAt | ||
| ? { createdAt: lastUser.createdAt.toISOString(), id: lastUser.id } | ||
| hasMore && lastUser?.createdAtRaw | ||
| ? { createdAt: lastUser.createdAtRaw, id: lastUser.id } | ||
| : null; | ||
|
|
||
| return { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation uses
users.find()to get the selected user's name on every render. This can be inefficient for large lists of users, which is the scenario this PR addresses. A linear search on every render could lead to performance issues.To optimize this, you can create a
Mapof user IDs to names usinguseMemo. This will provide a more performant O(1) lookup.Add this to your component: