Skip to content

Commit c5527cf

Browse files
committed
refactor(dashboard): replace complex API calls with simplified versions for groups and admins across components
1 parent 5f73aef commit c5527cf

File tree

8 files changed

+337
-57
lines changed

8 files changed

+337
-57
lines changed

dashboard/src/components/bulk/bulk-flow.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import { useState, useRef, useEffect } from 'react'
44
import {
5-
useGetAllGroups,
6-
useGetUsers,
7-
useGetAdmins,
5+
useGetGroupsSimple,
6+
useGetUsersSimple,
7+
useGetAdminsSimple,
88
useBulkModifyUsersProxySettings,
99
useBulkModifyUsersDatalimit,
1010
useBulkModifyUsersExpire,
@@ -105,9 +105,9 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
105105
setExpireSeconds(seconds)
106106
}, [expireAmount, expireUnit])
107107

108-
const { data: groupsData, isLoading: groupsLoading } = useGetAllGroups({ limit: PAGE_SIZE, offset: 0 })
109-
const { data: usersData, isLoading: usersLoading } = useGetUsers({ limit: PAGE_SIZE, offset: 0, search: debouncedUserSearch || undefined })
110-
const { data: adminsData, isLoading: adminsLoading } = useGetAdmins({ limit: PAGE_SIZE, offset: 0, username: debouncedAdminSearch || undefined })
108+
const { data: groupsData, isLoading: groupsLoading } = useGetGroupsSimple({ limit: PAGE_SIZE, offset: 0, all: true })
109+
const { data: usersData, isLoading: usersLoading } = useGetUsersSimple({ limit: PAGE_SIZE, offset: 0, search: debouncedUserSearch || undefined })
110+
const { data: adminsData, isLoading: adminsLoading } = useGetAdminsSimple({ limit: PAGE_SIZE, offset: 0, username: debouncedAdminSearch || undefined })
111111

112112
const statusOptions: { value: UserStatus; label: string }[] = [
113113
{ value: 'active', label: t('status.active', { defaultValue: 'Active' }) },
@@ -806,7 +806,7 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
806806
<SelectorPanel
807807
icon={Shield}
808808
title={t('bulk.selectAdmins', { defaultValue: 'Select Admins' })}
809-
items={(adminsData?.admins || []).filter(a => typeof a.id === 'number' && typeof a.username === 'string').map(a => ({ id: a.id as number, username: a.username as string }))}
809+
items={adminsData?.admins || []}
810810
selected={selectedAdmins}
811811
setSelected={setSelectedAdmins}
812812
search={adminSearch}

dashboard/src/components/charts/user-sub-update-pie-chart.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Skeleton } from '@/components/ui/skeleton'
55
import { Badge } from '@/components/ui/badge'
66
import useDirDetection from '@/hooks/use-dir-detection'
77
import { useTheme } from 'next-themes'
8-
import { type GetUsersSubUpdateChartParams, useGetAdmins, useGetUsersSubUpdateChart, type UserSubscriptionUpdateChartSegment } from '@/service/api'
8+
import { type GetUsersSubUpdateChartParams, useGetAdminsSimple, useGetUsersSubUpdateChart, type UserSubscriptionUpdateChartSegment } from '@/service/api'
99
import { numberWithCommas } from '@/utils/formatByte'
1010
import { TrendingUp, Users } from 'lucide-react'
1111
import { useEffect, useMemo, useState } from 'react'
@@ -144,7 +144,7 @@ function UserSubUpdatePieChart({ username, adminId }: UserSubUpdatePieChartProps
144144
}
145145
}, [adminId])
146146

147-
const { data: admins, isLoading: isLoadingAdmins } = useGetAdmins(undefined, {
147+
const { data: admins, isLoading: isLoadingAdmins } = useGetAdminsSimple({ all: true }, {
148148
query: {
149149
enabled: true,
150150
staleTime: 5 * 60 * 1000,

dashboard/src/components/common/admin-filter-combobox.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
55
import useDirDetection from '@/hooks/use-dir-detection'
66
import { useDebouncedSearch } from '@/hooks/use-debounced-search'
77
import { cn } from '@/lib/utils'
8-
import { type AdminDetails, useGetAdmins } from '@/service/api'
9-
import { Check, ChevronDown, Loader2, Sigma, UserCog, UserRound } from 'lucide-react'
8+
import { type AdminDetails, type AdminSimple, useGetAdminsSimple } from '@/service/api'
9+
import { Check, ChevronDown, Loader2, Sigma, UserRound } from 'lucide-react'
1010
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
1111
import { useTranslation } from 'react-i18next'
1212

@@ -25,7 +25,7 @@ export default function AdminFilterCombobox({ value, onValueChange, onAdminSelec
2525

2626
const [open, setOpen] = useState(false)
2727
const [offset, setOffset] = useState(0)
28-
const [admins, setAdmins] = useState<AdminDetails[]>([])
28+
const [admins, setAdmins] = useState<AdminSimple[]>([])
2929
const [hasMore, setHasMore] = useState(true)
3030
const [isLoadingMore, setIsLoadingMore] = useState(false)
3131
const listRef = useRef<HTMLDivElement>(null)
@@ -38,7 +38,7 @@ export default function AdminFilterCombobox({ value, onValueChange, onAdminSelec
3838
setIsLoadingMore(false)
3939
}, [adminSearch])
4040

41-
const { data: fetchedAdminsResponse, isLoading, isFetching } = useGetAdmins(
41+
const { data: fetchedAdminsResponse, isLoading, isFetching } = useGetAdminsSimple(
4242
{
4343
limit: PAGE_SIZE,
4444
offset,
@@ -57,7 +57,7 @@ export default function AdminFilterCombobox({ value, onValueChange, onAdminSelec
5757
const fetchedAdmins = (fetchedAdminsResponse.admins || []).filter(admin => admin.username !== 'system')
5858
setAdmins(prev => {
5959
const merged = offset === 0 ? fetchedAdmins : [...prev, ...fetchedAdmins]
60-
const byUsername = new Map<string, AdminDetails>()
60+
const byUsername = new Map<string, AdminSimple>()
6161
merged.forEach(admin => {
6262
byUsername.set(admin.username, admin)
6363
})
@@ -97,7 +97,7 @@ export default function AdminFilterCombobox({ value, onValueChange, onAdminSelec
9797
<AvatarFallback className="bg-muted text-xs font-medium">{value === 'all' ? <Sigma className="h-3 w-3" /> : triggerLabel.charAt(0).toUpperCase()}</AvatarFallback>
9898
</Avatar>
9999
<span className="truncate">{triggerLabel}</span>
100-
{value !== 'all' && selectedAdmin && <div className="flex-shrink-0">{selectedAdmin.is_sudo ? <UserCog className="h-3 w-3 text-primary" /> : <UserRound className="h-3 w-3 text-primary" />}</div>}
100+
{value !== 'all' && selectedAdmin && <div className="flex-shrink-0"><UserRound className="h-3 w-3 text-primary" /></div>}
101101
</div>
102102
<ChevronDown className="ml-1 h-3 w-3 flex-shrink-0 text-muted-foreground" />
103103
</Button>
@@ -141,7 +141,10 @@ export default function AdminFilterCombobox({ value, onValueChange, onAdminSelec
141141
value={admin.username}
142142
onSelect={() => {
143143
onValueChange(admin.username)
144-
onAdminSelect?.(admin)
144+
onAdminSelect?.({
145+
...admin,
146+
is_sudo: false,
147+
})
145148
setOpen(false)
146149
}}
147150
className={cn('flex min-w-0 items-center gap-2 px-2 py-1.5 text-xs sm:text-sm', dir === 'rtl' ? 'flex-row-reverse' : 'flex-row')}
@@ -151,7 +154,7 @@ export default function AdminFilterCombobox({ value, onValueChange, onAdminSelec
151154
</Avatar>
152155
<span className="flex-1 truncate">{admin.username}</span>
153156
<div className="flex flex-shrink-0 items-center gap-1">
154-
{admin.is_sudo ? <UserCog className="h-3 w-3 text-primary" /> : <UserRound className="h-3 w-3 text-primary" />}
157+
<UserRound className="h-3 w-3 text-primary" />
155158
{value === admin.username && <Check className="h-3 w-3 text-primary" />}
156159
</div>
157160
</CommandItem>

dashboard/src/components/common/admins-selector.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Checkbox } from '@/components/ui/checkbox'
22
import { FormItem, FormMessage } from '@/components/ui/form'
33
import { Input } from '@/components/ui/input'
44
import { Skeleton } from '@/components/ui/skeleton'
5-
import { useGetAdmins } from '@/service/api'
5+
import { useGetAdminsSimple } from '@/service/api'
66
import { Search } from 'lucide-react'
77
import { useState } from 'react'
88
import { Control, FieldPath, FieldValues, useController } from 'react-hook-form'
@@ -26,7 +26,7 @@ export default function AdminsSelector<T extends FieldValues>({ control, name, o
2626
name,
2727
})
2828

29-
const { data: adminsData, isLoading: adminsLoading } = useGetAdmins(undefined, {
29+
const { data: adminsData, isLoading: adminsLoading } = useGetAdminsSimple({ all: true }, {
3030
query: {
3131
staleTime: 5 * 60 * 1000, // 5 minutes
3232
gcTime: 10 * 60 * 1000, // 10 minutes

dashboard/src/components/common/groups-selector.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Checkbox } from '@/components/ui/checkbox'
22
import { FormItem, FormMessage } from '@/components/ui/form'
33
import { Input } from '@/components/ui/input'
44
import { Skeleton } from '@/components/ui/skeleton'
5-
import { useGetAllGroups } from '@/service/api'
5+
import { useGetGroupsSimple } from '@/service/api'
66
import { Search } from 'lucide-react'
77
import { useState } from 'react'
88
import { Control, FieldPath, FieldValues, useController } from 'react-hook-form'
@@ -29,7 +29,7 @@ export default function GroupsSelector<T extends FieldValues>({ control, name, o
2929
name,
3030
})
3131

32-
const { data: groupsData, isLoading: groupsLoading } = useGetAllGroups(undefined, {
32+
const { data: groupsData, isLoading: groupsLoading } = useGetGroupsSimple({ all: true }, {
3333
query: {
3434
staleTime: 5 * 60 * 1000, // 5 minutes
3535
gcTime: 10 * 60 * 1000, // 10 minutes

dashboard/src/components/dialogs/advance-search-modal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import GroupsSelector from '@/components/common/groups-selector.tsx'
1212
import AdminsSelector from '@/components/common/admins-selector.tsx'
1313
import { Badge } from '@/components/ui/badge.tsx'
1414
import { X } from 'lucide-react'
15-
import { useGetAllGroups } from '@/service/api'
15+
import { useGetGroupsSimple } from '@/service/api'
1616
import type { AdvanceSearchFormValue } from '@/components/forms/advance-search-form'
1717

1818
interface AdvanceSearchModalProps {
@@ -26,7 +26,7 @@ export default function AdvanceSearchModal({ isDialogOpen, onOpenChange, form, o
2626
const dir = useDirDetection()
2727
const { t } = useTranslation()
2828

29-
const { data: groupsData } = useGetAllGroups(undefined, {
29+
const { data: groupsData } = useGetGroupsSimple({ all: true }, {
3030
query: {
3131
staleTime: 5 * 60 * 1000, // 5 minutes
3232
gcTime: 10 * 60 * 1000, // 10 minutes

dashboard/src/components/dialogs/user-modal.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
getGetGeneralSettingsQueryKey,
2020
useCreateUser,
2121
useCreateUserFromTemplate,
22+
useGetGroupsSimple,
2223
useGetUsers,
2324
useGetUserTemplates,
2425
useModifyUser,
@@ -510,6 +511,21 @@ export default function UserModal({ isDialogOpen, onOpenChange, form, editingUse
510511
},
511512
})
512513

514+
// Prefetch lightweight groups while modal is open so the Groups tab can render immediately.
515+
useGetGroupsSimple(
516+
{ all: true },
517+
{
518+
query: {
519+
staleTime: 5 * 60 * 1000,
520+
gcTime: 10 * 60 * 1000,
521+
refetchOnWindowFocus: true,
522+
refetchOnMount: true,
523+
refetchOnReconnect: true,
524+
enabled: isDialogOpen,
525+
},
526+
},
527+
)
528+
513529
const { data: generalSettings } = useQuery({
514530
queryKey: getGetGeneralSettingsQueryKey(),
515531
queryFn: () => getGeneralSettings(),

0 commit comments

Comments
 (0)