chore: run bun format to automatically format the frontend code

This commit is contained in:
t0ng7u
2026-07-01 06:38:41 +08:00
parent e514db20f7
commit 5bf3468362
679 changed files with 2719 additions and 1717 deletions
+2 -1
View File
@@ -16,8 +16,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { api } from '@/lib/api'
import type { PermissionCatalog } from '@/lib/admin-permissions'
import { api } from '@/lib/api'
import type {
User,
GetUsersParams,
@@ -17,7 +17,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { type Table } from '@tanstack/react-table'
import { DataTableBulkActions as BulkActionsToolbar } from '@/components/data-table'
import { type User } from '../types'
interface DataTableBulkActionsProps {
@@ -16,7 +16,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useState } from 'react'
import type { Row } from '@tanstack/react-table'
import {
Pencil,
@@ -30,22 +29,25 @@ import {
Link2,
CreditCard,
} from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { DataTableRowActionMenu } from '@/components/data-table/core/row-action-menu'
import { Button } from '@/components/ui/button'
import {
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
} from '@/components/ui/dropdown-menu'
import { DataTableRowActionMenu } from '@/components/data-table/core/row-action-menu'
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { UserSubscriptionsDialog } from '@/features/subscriptions/components/dialogs/user-subscriptions-dialog'
import { manageUser, resetUserPasskey, resetUserTwoFA } from '../api'
import {
USER_STATUS,
@@ -155,7 +157,10 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
<TooltipContent>{t('Edit')}</TooltipContent>
</Tooltip>
<DataTableRowActionMenu ariaLabel={t('Open menu')} contentClassName='w-48'>
<DataTableRowActionMenu
ariaLabel={t('Open menu')}
contentClassName='w-48'
>
{isDisabled ? (
<DropdownMenuItem onClick={() => handleManage('enable')}>
{t('Enable')}
@@ -175,88 +180,88 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
</DropdownMenuItem>
)}
{isAdmin && !isRoot && (
<DropdownMenuItem onClick={() => handleManage('demote')}>
{t('Demote')}
<DropdownMenuShortcut>
<ArrowDown size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
)}
{!isAdmin && (
<DropdownMenuItem onClick={() => handleManage('promote')}>
{t('Promote')}
<DropdownMenuShortcut>
<ArrowUp size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
)}
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setBindingDialogOpen(true)
}}
>
{t('Manage Bindings')}
{isAdmin && !isRoot && (
<DropdownMenuItem onClick={() => handleManage('demote')}>
{t('Demote')}
<DropdownMenuShortcut>
<Link2 size={16} />
<ArrowDown size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
)}
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setSubscriptionsDialogOpen(true)
}}
>
{t('Manage Subscriptions')}
{!isAdmin && (
<DropdownMenuItem onClick={() => handleManage('promote')}>
{t('Promote')}
<DropdownMenuShortcut>
<CreditCard size={16} />
<ArrowUp size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setBindingDialogOpen(true)
}}
>
{t('Manage Bindings')}
<DropdownMenuShortcut>
<Link2 size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setResetPasskeyOpen(true)
}}
disabled={isRoot}
>
{t('Reset Passkey')}
<DropdownMenuShortcut>
<KeyRound size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setSubscriptionsDialogOpen(true)
}}
>
{t('Manage Subscriptions')}
<DropdownMenuShortcut>
<CreditCard size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setResetTwoFAOpen(true)
}}
disabled={isRoot}
>
{t('Reset 2FA')}
<DropdownMenuShortcut>
<ShieldAlert size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuSeparator />
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setResetPasskeyOpen(true)
}}
disabled={isRoot}
>
{t('Reset Passkey')}
<DropdownMenuShortcut>
<KeyRound size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem
onClick={handleDelete}
className='text-destructive focus:text-destructive'
disabled={isRoot}
>
{t('Delete')}
<DropdownMenuShortcut>
<Trash2 size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem
onSelect={(event) => {
event.preventDefault()
setResetTwoFAOpen(true)
}}
disabled={isRoot}
>
{t('Reset 2FA')}
<DropdownMenuShortcut>
<ShieldAlert size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={handleDelete}
className='text-destructive focus:text-destructive'
disabled={isRoot}
>
{t('Delete')}
<DropdownMenuShortcut>
<Trash2 size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
</DataTableRowActionMenu>
<ConfirmDialog
@@ -16,7 +16,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useState, useEffect, useCallback, useMemo } from 'react'
import {
Mail,
Globe,
@@ -28,10 +27,14 @@ import {
Eye,
EyeOff,
} from 'lucide-react'
import { useState, useEffect, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { SiGithub, SiDiscord } from 'react-icons/si'
import { toast } from 'sonner'
import { api } from '@/lib/api'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { Dialog } from '@/components/dialog'
import { StatusBadge } from '@/components/status-badge'
import { Button } from '@/components/ui/button'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Separator } from '@/components/ui/separator'
@@ -41,9 +44,8 @@ import {
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { Dialog } from '@/components/dialog'
import { StatusBadge } from '@/components/status-badge'
import { api } from '@/lib/api'
import {
getUser,
getUserOAuthBindings,
@@ -19,13 +19,15 @@ For commercial licensing, please contact support@quantumnous.com
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { getCurrencyDisplay, getCurrencyLabel } from '@/lib/currency'
import { formatQuota, parseQuotaFromDollars } from '@/lib/format'
import { cn } from '@/lib/utils'
import { Dialog } from '@/components/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Dialog } from '@/components/dialog'
import { getCurrencyDisplay, getCurrencyLabel } from '@/lib/currency'
import { formatQuota, parseQuotaFromDollars } from '@/lib/format'
import { cn } from '@/lib/utils'
import { adjustUserQuota } from '../api'
import type { QuotaAdjustMode } from '../types'
@@ -18,8 +18,12 @@ For commercial licensing, please contact support@quantumnous.com
*/
import { type ColumnDef } from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
import { formatQuota, formatTimestamp } from '@/lib/format'
import { cn } from '@/lib/utils'
import { BadgeCell } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { LongText } from '@/components/long-text'
import { StatusBadge } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
import { Checkbox } from '@/components/ui/checkbox'
import { Progress } from '@/components/ui/progress'
import {
@@ -27,11 +31,9 @@ import {
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip'
import { BadgeCell } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { LongText } from '@/components/long-text'
import { StatusBadge } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
import { formatQuota, formatTimestamp } from '@/lib/format'
import { cn } from '@/lib/utils'
import {
USER_STATUS,
USER_STATUSES,
@@ -19,7 +19,9 @@ For commercial licensing, please contact support@quantumnous.com
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { deleteUser } from '../api'
import { ERROR_MESSAGES } from '../constants'
import { getUserActionMessage } from '../lib'
@@ -16,24 +16,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { useQuery } from '@tanstack/react-query'
import { Pencil } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import {
ADMIN_PERMISSION_ACTIONS,
ADMIN_PERMISSION_RESOURCES,
EMPTY_PERMISSION_CATALOG,
hasPermission,
normalizeAdminPermissions,
} from '@/lib/admin-permissions'
import { getCurrencyDisplay, getCurrencyLabel } from '@/lib/currency'
import { formatQuota, parseQuotaFromDollars } from '@/lib/format'
import { ROLE } from '@/lib/roles'
import { useAuthStore } from '@/stores/auth-store'
SideDrawerSection,
sideDrawerContentClassName,
sideDrawerFooterClassName,
sideDrawerFormClassName,
sideDrawerHeaderClassName,
} from '@/components/drawer-layout'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import {
@@ -66,12 +63,17 @@ import {
} from '@/components/ui/sheet'
import { Textarea } from '@/components/ui/textarea'
import {
SideDrawerSection,
sideDrawerContentClassName,
sideDrawerFooterClassName,
sideDrawerFormClassName,
sideDrawerHeaderClassName,
} from '@/components/drawer-layout'
ADMIN_PERMISSION_ACTIONS,
ADMIN_PERMISSION_RESOURCES,
EMPTY_PERMISSION_CATALOG,
hasPermission,
normalizeAdminPermissions,
} from '@/lib/admin-permissions'
import { getCurrencyDisplay, getCurrencyLabel } from '@/lib/currency'
import { formatQuota, parseQuotaFromDollars } from '@/lib/format'
import { ROLE } from '@/lib/roles'
import { useAuthStore } from '@/stores/auth-store'
import {
createUser,
updateUser,
@@ -451,88 +453,93 @@ export function UsersMutateDrawer({
{canEditAdminPermissions &&
targetIsAdmin &&
permissionCatalog.resources.length > 0 && (
<SideDrawerSection>
<h3 className='text-sm font-medium'>
{t('Admin Permissions')}
</h3>
<p className='text-muted-foreground text-xs'>
{t(
'Default administrator permissions can be overridden for this user.'
)}
</p>
<FormField
control={form.control}
name='admin_permissions'
render={({ field }) => {
const selected = normalizeAdminPermissions(
field.value,
permissionCatalog
)
return (
<FormItem>
<div className='space-y-3'>
{permissionCatalog.resources.map((resource) => (
<div
key={resource.resource}
className='space-y-2 rounded-md border p-3'
>
<div className='text-sm font-medium'>
{t(resource.label_key)}
</div>
<div className='space-y-2'>
{resource.actions.map((option) => (
<label
key={option.action}
className='flex items-start gap-3'
>
<Checkbox
checked={
selected[resource.resource]?.[
option.action
] === true
}
onCheckedChange={(checked) => {
field.onChange({
...selected,
[resource.resource]: {
...selected[resource.resource],
[option.action]: checked === true,
},
})
}}
/>
<span className='flex flex-col gap-1'>
<span className='text-sm font-medium'>
{t(option.label_key)}
</span>
<span className='text-muted-foreground text-xs'>
{t(option.description_key)}
</span>
</span>
</label>
))}
</div>
</div>
))}
</div>
<FormMessage />
</FormItem>
)
}}
/>
{currentUser && (
<SideDrawerSection>
<h3 className='text-sm font-medium'>
{t('Admin Permissions')}
</h3>
<p className='text-muted-foreground text-xs'>
{hasPermission(
currentUser,
ADMIN_PERMISSION_RESOURCES.CHANNEL,
ADMIN_PERMISSION_ACTIONS.SENSITIVE_WRITE
)
? t('Your account can edit sensitive channel settings.')
: t('Your account cannot edit sensitive channel settings.')}
{t(
'Default administrator permissions can be overridden for this user.'
)}
</p>
)}
</SideDrawerSection>
)}
<FormField
control={form.control}
name='admin_permissions'
render={({ field }) => {
const selected = normalizeAdminPermissions(
field.value,
permissionCatalog
)
return (
<FormItem>
<div className='space-y-3'>
{permissionCatalog.resources.map((resource) => (
<div
key={resource.resource}
className='space-y-2 rounded-md border p-3'
>
<div className='text-sm font-medium'>
{t(resource.label_key)}
</div>
<div className='space-y-2'>
{resource.actions.map((option) => (
<label
key={option.action}
className='flex items-start gap-3'
>
<Checkbox
checked={
selected[resource.resource]?.[
option.action
] === true
}
onCheckedChange={(checked) => {
field.onChange({
...selected,
[resource.resource]: {
...selected[resource.resource],
[option.action]:
checked === true,
},
})
}}
/>
<span className='flex flex-col gap-1'>
<span className='text-sm font-medium'>
{t(option.label_key)}
</span>
<span className='text-muted-foreground text-xs'>
{t(option.description_key)}
</span>
</span>
</label>
))}
</div>
</div>
))}
</div>
<FormMessage />
</FormItem>
)
}}
/>
{currentUser && (
<p className='text-muted-foreground text-xs'>
{hasPermission(
currentUser,
ADMIN_PERMISSION_RESOURCES.CHANNEL,
ADMIN_PERMISSION_ACTIONS.SENSITIVE_WRITE
)
? t(
'Your account can edit sensitive channel settings.'
)
: t(
'Your account cannot edit sensitive channel settings.'
)}
</p>
)}
</SideDrawerSection>
)}
{/* Binding Information (Read-only) */}
{isUpdate && (
@@ -18,7 +18,9 @@ For commercial licensing, please contact support@quantumnous.com
*/
import { Plus } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { useUsers } from './users-provider'
export function UsersPrimaryButtons() {
@@ -17,7 +17,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import React, { useState } from 'react'
import useDialogState from '@/hooks/use-dialog'
import { type User, type UsersDialogType } from '../types'
type UsersContextType = {
+4 -2
View File
@@ -18,16 +18,18 @@ For commercial licensing, please contact support@quantumnous.com
*/
import { useQuery } from '@tanstack/react-query'
import { getRouteApi } from '@tanstack/react-router'
import { useMediaQuery } from '@/hooks'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { useTableUrlState } from '@/hooks/use-table-url-state'
import {
DISABLED_ROW_DESKTOP,
DISABLED_ROW_MOBILE,
DataTablePage,
useDataTable,
} from '@/components/data-table'
import { useMediaQuery } from '@/hooks'
import { useTableUrlState } from '@/hooks/use-table-url-state'
import { getUsers, searchUsers } from '../api'
import {
USER_STATUS,
+1
View File
@@ -17,6 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { Shield, User, Users } from 'lucide-react'
import type { User as UserType } from './types'
// ============================================================================
+2
View File
@@ -17,7 +17,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useTranslation } from 'react-i18next'
import { SectionPageLayout } from '@/components/layout'
import { UsersDeleteDialog } from './components/users-delete-dialog'
import { UsersMutateDrawer } from './components/users-mutate-drawer'
import { UsersPrimaryButtons } from './components/users-primary-buttons'
+6 -2
View File
@@ -17,13 +17,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { z } from 'zod'
import { quotaUnitsToDollars } from '@/lib/format'
import {
type PermissionCatalog,
type AdminPermissionMatrix,
normalizeAdminPermissions,
} from '@/lib/admin-permissions'
import { quotaUnitsToDollars } from '@/lib/format'
import { ROLE } from '@/lib/roles'
import { DEFAULT_GROUP } from '../constants'
import { type UserFormData, type User } from '../types'
@@ -39,7 +41,9 @@ export const userFormSchema = z.object({
quota_dollars: z.number().min(0).optional(),
group: z.string().optional(),
remark: z.string().optional(),
admin_permissions: z.record(z.string(), z.record(z.string(), z.boolean())).optional(),
admin_permissions: z
.record(z.string(), z.record(z.string(), z.boolean()))
.optional(),
})
export type UserFormValues = z.infer<typeof userFormSchema>
+4 -1
View File
@@ -17,6 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { z } from 'zod'
import type { AdminPermissionMatrix } from '@/lib/admin-permissions'
// ============================================================================
@@ -58,7 +59,9 @@ export const userSchema = z.object({
last_login_at: z.number().optional(),
DeletedAt: z.any().nullable().optional(),
remark: z.string().optional(),
admin_permissions: z.record(z.string(), z.record(z.string(), z.boolean())).optional(),
admin_permissions: z
.record(z.string(), z.record(z.string(), z.boolean()))
.optional(),
})
export type User = z.infer<typeof userSchema>