feat(notification): manage push applications
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { useState } from 'react'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import type { ColumnDef } from '@tanstack/react-table'
|
||||
import { toast } from 'sonner'
|
||||
import { deletePushApp, fetchPushApps, verifyPushApp } from '@/api/modules/push-apps'
|
||||
import type { PushApp } from '@/api/types'
|
||||
import { PERM, requirePermission } from '@/auth/permissions'
|
||||
import { useCan } from '@/auth/store'
|
||||
import { ConfirmDialog } from '@/components/confirm-dialog'
|
||||
import { DataTable } from '@/components/data-table/data-table'
|
||||
import { PageHeader } from '@/components/page-header'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { PushAppEditSheet } from '@/features/notification/push-app-edit-sheet'
|
||||
import { handleApiError } from '@/lib/errors'
|
||||
|
||||
export const Route = createFileRoute('/_authed/push-apps')({ beforeLoad: () => requirePermission(PERM.NOTIFICATION_READ), component: PushAppsPage })
|
||||
|
||||
function PushAppsPage() {
|
||||
const canManage = useCan(PERM.PUSH_APP_MANAGE)
|
||||
const queryClient = useQueryClient()
|
||||
const query = useQuery({ queryKey: ['push-apps'], queryFn: fetchPushApps })
|
||||
const [editing, setEditing] = useState<PushApp | null>(null)
|
||||
const [creating, setCreating] = useState(false)
|
||||
const refresh = () => { void queryClient.invalidateQueries({ queryKey: ['push-apps'] }) }
|
||||
const verify = async (app: PushApp) => { try { const response = await verifyPushApp(app.id); const failed = Object.entries(response.data.checks).filter(([, ok]) => !ok).map(([key]) => key); response.data.ok ? toast.success('凭证验证通过') : toast.error(`验证未通过:${failed.join(', ')}`) } catch (error) { handleApiError(error) } }
|
||||
const remove = async (app: PushApp) => { try { await deletePushApp(app.id); toast.success('推送应用已删除'); refresh() } catch (error) { handleApiError(error) } }
|
||||
const columns: ColumnDef<PushApp>[] = [
|
||||
{ header: '应用', cell: ({ row }) => <div><div className="font-medium">{row.original.label ?? row.original.app_key}</div><code className="text-xs text-muted-foreground">{row.original.app_key}</code></div> },
|
||||
{ header: '通道', cell: ({ row }) => <Badge variant="secondary">{row.original.provider.toUpperCase()}</Badge> },
|
||||
{ header: '平台', accessorKey: 'platform' },
|
||||
{ header: '凭证', cell: ({ row }) => row.original.credentials_present ? <Badge className="bg-emerald-500/12 text-emerald-700">已放置</Badge> : <Badge variant="destructive">缺失</Badge> },
|
||||
{ header: '状态', cell: ({ row }) => row.original.is_active ? '启用' : '停用' },
|
||||
{ header: '操作', cell: ({ row }) => <div className="flex gap-1.5">{canManage && <Button size="sm" variant="ghost" onClick={() => void verify(row.original)}>验证</Button>}{canManage && row.original.provider !== 'mipush' && <Button size="sm" variant="outline" onClick={() => setEditing(row.original)}>编辑</Button>}{canManage && <ConfirmDialog trigger={<Button size="sm" variant="destructive">删除</Button>} title={`删除 ${row.original.app_key}/${row.original.provider}?`} confirmLabel="删除" destructive onConfirm={() => remove(row.original)} />}</div> },
|
||||
]
|
||||
return <div><PageHeader title="推送应用" description="管理每个应用和推送通道的凭证与路由" actions={canManage ? <Button onClick={() => setCreating(true)}>新建推送应用</Button> : undefined} /><PushAppEditSheet app={editing} creating={creating} onOpenChange={(open) => { if (!open) { setEditing(null); setCreating(false) } }} onSaved={refresh} /><DataTable columns={columns} data={query.data?.data ?? []} loading={query.isLoading} /></div>
|
||||
}
|
||||
Reference in New Issue
Block a user