From 289966e7e9f3a9b0301986a1c4ab665f3daa2b26 Mon Sep 17 00:00:00 2001 From: Bianca Date: Tue, 8 Sep 2026 20:02:55 +0200 Subject: [PATCH 1/3] feat: add group link reports management with pending and resolved views --- src/components/dashboard-navigation.ts | 11 + src/components/data-toolbar.tsx | 4 +- .../group-link-reports/reports-page.tsx | 222 ++++++++++++++++++ .../group-link-reports/reports.functions.ts | 22 ++ src/features/telegram/groups-page.tsx | 5 +- .../whatsapp/whatsapp-groups-page.tsx | 5 +- src/lib/api/types.ts | 2 + src/routeTree.gen.ts | 44 ++++ src/routes/dashboard/reports/group-links.tsx | 16 ++ src/routes/dashboard/reports/resolved.tsx | 16 ++ src/routes/dashboard/telegram/groups.tsx | 4 + src/routes/dashboard/whatsapp/groups.tsx | 4 + 12 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 src/features/group-link-reports/reports-page.tsx create mode 100644 src/features/group-link-reports/reports.functions.ts create mode 100644 src/routes/dashboard/reports/group-links.tsx create mode 100644 src/routes/dashboard/reports/resolved.tsx diff --git a/src/components/dashboard-navigation.ts b/src/components/dashboard-navigation.ts index 450e157..1944b0d 100644 --- a/src/components/dashboard-navigation.ts +++ b/src/components/dashboard-navigation.ts @@ -1,7 +1,9 @@ import { BookOpen, + CircleCheck, CircleQuestionMark, Database, + Flag, FolderKanban, FolderTree, Globe, @@ -76,6 +78,15 @@ export const dashboardNavigation = [ { title: "Categories", url: "/dashboard/web/groups-by-label", icon: FolderTree }, ], }, + { + title: "Reports", + icon: Flag, + iconSrc: undefined, + items: [ + { title: "Reported", url: "/dashboard/reports/group-links", icon: Flag }, + { title: "Resolved", url: "/dashboard/reports/resolved", icon: CircleCheck }, + ], + }, ] as const satisfies readonly DashboardNavigationCategory[] export const accountNavigation = { diff --git a/src/components/data-toolbar.tsx b/src/components/data-toolbar.tsx index ea5ea2a..13890d3 100644 --- a/src/components/data-toolbar.tsx +++ b/src/components/data-toolbar.tsx @@ -12,6 +12,7 @@ export function DataToolbar({ total, onSearch, searchPlaceholder, + defaultSearchValue, action, children, eyebrow = "Directory", @@ -22,12 +23,13 @@ export function DataToolbar({ total?: number onSearch?: (value: string) => void searchPlaceholder?: string + defaultSearchValue?: string action?: ReactNode children?: ReactNode eyebrow?: string }) { const searchId = useId() - const [searchValue, setSearchValue] = useState("") + const [searchValue, setSearchValue] = useState(defaultSearchValue ?? "") const deferredSearchValue = useDeferredValue(searchValue) const onSearchRef = useRef(onSearch) onSearchRef.current = onSearch diff --git a/src/features/group-link-reports/reports-page.tsx b/src/features/group-link-reports/reports-page.tsx new file mode 100644 index 0000000..3e8e676 --- /dev/null +++ b/src/features/group-link-reports/reports-page.tsx @@ -0,0 +1,222 @@ +import { useRouter } from "@tanstack/react-router" +import { useServerFn } from "@tanstack/react-start" +import { Check, Flag, X } from "lucide-react" +import { useState } from "react" +import { toast } from "sonner" + +import { EmptyState } from "@/components/empty-state" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { DataTableHead, Table, TableBody, TableCell, TableHeader, TableRow, TableSurface } from "@/components/ui/table" +import { labelPathToUrlSegments } from "@/features/group-labels/label-tree" +import { dismissGroupLinkReport, resolveGroupLinkReport } from "@/features/group-link-reports/reports.functions" +import type { GroupLinkReport } from "@/lib/api/types" + +const REPORT_TYPE_LABEL = { + broken_link: "Broken link", + missing: "Missing group", +} satisfies Record + +const TYPE_LABEL = { + tg: "Telegram", + wa: "WhatsApp", +} satisfies Record, string> + +const STATUS_LABEL = { + pending: "Pending", + resolved: "Resolved", + dismissed: "Dismissed", +} satisfies Record + +function groupsPageUrl(type: NonNullable) { + return type === "tg" ? "/dashboard/telegram/groups" : "/dashboard/whatsapp/groups" +} + +function labelCategoryUrl(label: string) { + return `/dashboard/web/groups-by-label/${labelPathToUrlSegments(label).join("/")}` +} + +function missingLabel(report: GroupLinkReport) { + return report.label ?? "—" +} + +/** Where clicking a report should go: the problematic group itself for a broken link, or the category the + * missing group belongs to, following its label path. */ +function reportTarget(report: GroupLinkReport): { to: string; search?: { q: string } } | null { + if (report.reportType === "broken_link") { + if (!report.type) return null + return { to: groupsPageUrl(report.type), search: report.groupTitle ? { q: report.groupTitle } : undefined } + } + if (!report.label) return null + return { to: labelCategoryUrl(report.label) } +} + +type ReportGroup = { + key: string + latest: GroupLinkReport + ids: number[] + count: number +} + +function groupReports(reports: GroupLinkReport[]): ReportGroup[] { + const groups = new Map() + + for (const report of reports) { + const key = + report.reportType === "broken_link" + ? `broken_link:${report.type}:${report.groupId}` + : `missing:${report.label}` + + const existing = groups.get(key) + if (!existing) { + groups.set(key, { key, latest: report, ids: [report.id], count: 1 }) + continue + } + + existing.ids.push(report.id) + existing.count += 1 + if (new Date(report.createdAt) > new Date(existing.latest.createdAt)) existing.latest = report + } + + return [...groups.values()].sort( + (a, b) => new Date(a.latest.createdAt).getTime() - new Date(b.latest.createdAt).getTime() + ) +} + +export function GroupLinkReportsPage({ + loadedReports, + showActions = true, +}: { + loadedReports: GroupLinkReport[] + showActions?: boolean +}) { + const router = useRouter() + const resolve = useServerFn(resolveGroupLinkReport) + const dismiss = useServerFn(dismissGroupLinkReport) + const [pendingKey, setPendingKey] = useState(null) + + const reportGroups = groupReports(loadedReports) + + async function handleAction(group: ReportGroup, action: "resolve" | "dismiss") { + setPendingKey(group.key) + try { + await (action === "resolve" + ? resolve({ data: { ids: group.ids } }) + : dismiss({ data: { ids: group.ids } })) + await router.invalidate() + toast.success(action === "resolve" ? "Report resolved." : "Report dismissed.") + } catch (error) { + console.error(error) + toast.error("The report could not be updated. Check your permissions and try again.") + } finally { + setPendingKey(null) + } + } + + if (loadedReports.length === 0) { + return ( + + ) + } + + return ( + + + + + Reference + Issue + Details + {!showActions && Status} + Date + {showActions && Actions} + + + + {reportGroups.map((group) => { + const report = group.latest + const target = reportTarget(report) + const goToTarget = () => { + if (target) void router.navigate(target) + } + return ( + { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault() + goToTarget() + } + } + : undefined + } + > + +
+ {report.reportType === "broken_link" ? (report.groupTitle ?? "—") : missingLabel(report)} + {group.count > 1 && ( + + {group.count} + + )} +
+
+ +
+ {report.type && {TYPE_LABEL[report.type]}} + {REPORT_TYPE_LABEL[report.reportType]} +
+
+ + {report.reportType === "broken_link" ? (report.reportedLink ?? "—") : (report.details ?? "—")} + + {!showActions && ( + + + {STATUS_LABEL[report.status]} + + + )} + {new Date(report.createdAt).toLocaleDateString()} + {showActions && ( + event.stopPropagation()}> + + + + )} +
+ ) + })} +
+
+
+ ) +} diff --git a/src/features/group-link-reports/reports.functions.ts b/src/features/group-link-reports/reports.functions.ts new file mode 100644 index 0000000..a4a1499 --- /dev/null +++ b/src/features/group-link-reports/reports.functions.ts @@ -0,0 +1,22 @@ +import { createServerFn } from "@tanstack/react-start" +import { z } from "zod" + +import { adminMiddleware, groupWriteAdminMiddleware } from "@/server/auth.middleware" + +export const getPendingGroupLinkReports = createServerFn() + .middleware([adminMiddleware]) + .handler(({ context }) => context.backend.web.reports.list.query({ statuses: ["pending"] })) + +export const getResolvedGroupLinkReports = createServerFn() + .middleware([adminMiddleware]) + .handler(({ context }) => context.backend.web.reports.list.query({ statuses: ["resolved", "dismissed"] })) + +export const resolveGroupLinkReport = createServerFn({ method: "POST" }) + .middleware([groupWriteAdminMiddleware]) + .validator(z.object({ ids: z.array(z.number().int()).min(1) })) + .handler(({ data, context }) => context.backend.web.reports.resolve.mutate(data)) + +export const dismissGroupLinkReport = createServerFn({ method: "POST" }) + .middleware([groupWriteAdminMiddleware]) + .validator(z.object({ ids: z.array(z.number().int()).min(1) })) + .handler(({ data, context }) => context.backend.web.reports.dismiss.mutate(data)) diff --git a/src/features/telegram/groups-page.tsx b/src/features/telegram/groups-page.tsx index 84d7407..cd891c5 100644 --- a/src/features/telegram/groups-page.tsx +++ b/src/features/telegram/groups-page.tsx @@ -30,12 +30,14 @@ export function TelegramGroupsPage({ loadedGroups, loadedGroupLabels, loadedGroupsWithLabels, + initialQuery, }: { loadedGroups: TgGroup[] loadedGroupLabels: TgGroupLabel[] loadedGroupsWithLabels: GroupWithLabels[] + initialQuery?: string }) { - const [query, setQuery] = useState("") + const [query, setQuery] = useState(initialQuery ?? "") const [requiredLabels, setRequiredLabels] = useState([]) const [excludedLabels, setExcludedLabels] = useState([]) @@ -71,6 +73,7 @@ export function TelegramGroupsPage({ count={visibleGroups.length} total={loadedGroups.length} searchPlaceholder="Search by group name or tag…" + defaultSearchValue={initialQuery} onSearch={setQuery} > diff --git a/src/features/whatsapp/whatsapp-groups-page.tsx b/src/features/whatsapp/whatsapp-groups-page.tsx index df2fd20..14160bc 100644 --- a/src/features/whatsapp/whatsapp-groups-page.tsx +++ b/src/features/whatsapp/whatsapp-groups-page.tsx @@ -58,14 +58,16 @@ export function WhatsappGroupsPage({ loadedGroups, loadedGroupLabels, loadedGroupsWithLabels, + initialQuery, }: { loadedGroups: WaGroup[] loadedGroupLabels: TgGroupLabel[] loadedGroupsWithLabels: GroupWithLabels[] + initialQuery?: string }) { const router = useRouter() const setGroupVisibilityFn = useServerFn(setWhatsappGroupVisibility) - const [query, setQuery] = useState("") + const [query, setQuery] = useState(initialQuery ?? "") const [requiredLabels, setRequiredLabels] = useState([]) const [excludedLabels, setExcludedLabels] = useState([]) const [editingLabelsGroup, setEditingLabelsGroup] = useState(null) @@ -219,6 +221,7 @@ export function WhatsappGroupsPage({ count={visibleGroups.length} total={loadedGroups.length} searchPlaceholder="Search by group name…" + defaultSearchValue={initialQuery} onSearch={setQuery} action={} > diff --git a/src/lib/api/types.ts b/src/lib/api/types.ts index 1c3c8c9..3583875 100644 --- a/src/lib/api/types.ts +++ b/src/lib/api/types.ts @@ -22,3 +22,5 @@ export type WaGroup = ApiOutput["wa"]["groups"]["getAll"][number] /** A group (Telegram or WhatsApp) with its labels already resolved, from the cross-platform search router. */ export type GroupWithLabels = ApiOutput["groups"]["search"]["getAll"][number] + +export type GroupLinkReport = ApiOutput["web"]["reports"]["list"][number] diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index cd4bd23..a18677e 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -25,6 +25,8 @@ import { Route as DashboardWebFaqsRouteImport } from './routes/dashboard/web/faq import { Route as DashboardWebAssociationsRouteImport } from './routes/dashboard/web/associations' import { Route as DashboardTelegramGroupsRouteImport } from './routes/dashboard/telegram/groups' import { Route as DashboardTelegramGrantsRouteImport } from './routes/dashboard/telegram/grants' +import { Route as DashboardReportsResolvedRouteImport } from './routes/dashboard/reports/resolved' +import { Route as DashboardReportsGroupLinksRouteImport } from './routes/dashboard/reports/group-links' import { Route as DashboardAzureMembersRouteImport } from './routes/dashboard/azure/members' import { Route as DashboardAzureGroupsRouteImport } from './routes/dashboard/azure/groups' import { Route as ApiAuthSplatRouteImport } from './routes/api/auth/$' @@ -115,6 +117,18 @@ const DashboardTelegramGrantsRoute = DashboardTelegramGrantsRouteImport.update({ path: '/telegram/grants', getParentRoute: () => DashboardRoute, } as any) +const DashboardReportsResolvedRoute = + DashboardReportsResolvedRouteImport.update({ + id: '/reports/resolved', + path: '/reports/resolved', + getParentRoute: () => DashboardRoute, + } as any) +const DashboardReportsGroupLinksRoute = + DashboardReportsGroupLinksRouteImport.update({ + id: '/reports/group-links', + path: '/reports/group-links', + getParentRoute: () => DashboardRoute, + } as any) const DashboardAzureMembersRoute = DashboardAzureMembersRouteImport.update({ id: '/azure/members', path: '/azure/members', @@ -172,6 +186,8 @@ export interface FileRoutesByFullPath { '/api/auth/$': typeof ApiAuthSplatRoute '/dashboard/azure/groups': typeof DashboardAzureGroupsRoute '/dashboard/azure/members': typeof DashboardAzureMembersRoute + '/dashboard/reports/group-links': typeof DashboardReportsGroupLinksRoute + '/dashboard/reports/resolved': typeof DashboardReportsResolvedRoute '/dashboard/telegram/grants': typeof DashboardTelegramGrantsRoute '/dashboard/telegram/groups': typeof DashboardTelegramGroupsRoute '/dashboard/web/associations': typeof DashboardWebAssociationsRoute @@ -197,6 +213,8 @@ export interface FileRoutesByTo { '/api/auth/$': typeof ApiAuthSplatRoute '/dashboard/azure/groups': typeof DashboardAzureGroupsRoute '/dashboard/azure/members': typeof DashboardAzureMembersRoute + '/dashboard/reports/group-links': typeof DashboardReportsGroupLinksRoute + '/dashboard/reports/resolved': typeof DashboardReportsResolvedRoute '/dashboard/telegram/grants': typeof DashboardTelegramGrantsRoute '/dashboard/telegram/groups': typeof DashboardTelegramGroupsRoute '/dashboard/web/associations': typeof DashboardWebAssociationsRoute @@ -224,6 +242,8 @@ export interface FileRoutesById { '/api/auth/$': typeof ApiAuthSplatRoute '/dashboard/azure/groups': typeof DashboardAzureGroupsRoute '/dashboard/azure/members': typeof DashboardAzureMembersRoute + '/dashboard/reports/group-links': typeof DashboardReportsGroupLinksRoute + '/dashboard/reports/resolved': typeof DashboardReportsResolvedRoute '/dashboard/telegram/grants': typeof DashboardTelegramGrantsRoute '/dashboard/telegram/groups': typeof DashboardTelegramGroupsRoute '/dashboard/web/associations': typeof DashboardWebAssociationsRoute @@ -252,6 +272,8 @@ export interface FileRouteTypes { | '/api/auth/$' | '/dashboard/azure/groups' | '/dashboard/azure/members' + | '/dashboard/reports/group-links' + | '/dashboard/reports/resolved' | '/dashboard/telegram/grants' | '/dashboard/telegram/groups' | '/dashboard/web/associations' @@ -277,6 +299,8 @@ export interface FileRouteTypes { | '/api/auth/$' | '/dashboard/azure/groups' | '/dashboard/azure/members' + | '/dashboard/reports/group-links' + | '/dashboard/reports/resolved' | '/dashboard/telegram/grants' | '/dashboard/telegram/groups' | '/dashboard/web/associations' @@ -303,6 +327,8 @@ export interface FileRouteTypes { | '/api/auth/$' | '/dashboard/azure/groups' | '/dashboard/azure/members' + | '/dashboard/reports/group-links' + | '/dashboard/reports/resolved' | '/dashboard/telegram/grants' | '/dashboard/telegram/groups' | '/dashboard/web/associations' @@ -441,6 +467,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DashboardTelegramGrantsRouteImport parentRoute: typeof DashboardRoute } + '/dashboard/reports/resolved': { + id: '/dashboard/reports/resolved' + path: '/reports/resolved' + fullPath: '/dashboard/reports/resolved' + preLoaderRoute: typeof DashboardReportsResolvedRouteImport + parentRoute: typeof DashboardRoute + } + '/dashboard/reports/group-links': { + id: '/dashboard/reports/group-links' + path: '/reports/group-links' + fullPath: '/dashboard/reports/group-links' + preLoaderRoute: typeof DashboardReportsGroupLinksRouteImport + parentRoute: typeof DashboardRoute + } '/dashboard/azure/members': { id: '/dashboard/azure/members' path: '/azure/members' @@ -532,6 +572,8 @@ interface DashboardRouteChildren { DashboardIndexRoute: typeof DashboardIndexRoute DashboardAzureGroupsRoute: typeof DashboardAzureGroupsRoute DashboardAzureMembersRoute: typeof DashboardAzureMembersRoute + DashboardReportsGroupLinksRoute: typeof DashboardReportsGroupLinksRoute + DashboardReportsResolvedRoute: typeof DashboardReportsResolvedRoute DashboardTelegramGrantsRoute: typeof DashboardTelegramGrantsRoute DashboardTelegramGroupsRoute: typeof DashboardTelegramGroupsRoute DashboardWhatsappGroupsRoute: typeof DashboardWhatsappGroupsRoute @@ -545,6 +587,8 @@ const DashboardRouteChildren: DashboardRouteChildren = { DashboardIndexRoute: DashboardIndexRoute, DashboardAzureGroupsRoute: DashboardAzureGroupsRoute, DashboardAzureMembersRoute: DashboardAzureMembersRoute, + DashboardReportsGroupLinksRoute: DashboardReportsGroupLinksRoute, + DashboardReportsResolvedRoute: DashboardReportsResolvedRoute, DashboardTelegramGrantsRoute: DashboardTelegramGrantsRoute, DashboardTelegramGroupsRoute: DashboardTelegramGroupsRoute, DashboardWhatsappGroupsRoute: DashboardWhatsappGroupsRoute, diff --git a/src/routes/dashboard/reports/group-links.tsx b/src/routes/dashboard/reports/group-links.tsx new file mode 100644 index 0000000..206c2e7 --- /dev/null +++ b/src/routes/dashboard/reports/group-links.tsx @@ -0,0 +1,16 @@ +import { createFileRoute } from "@tanstack/react-router" + +import { DataPageSkeleton } from "@/components/loading-skeleton" +import { GroupLinkReportsPage } from "@/features/group-link-reports/reports-page" +import { getPendingGroupLinkReports } from "@/features/group-link-reports/reports.functions" + +export const Route = createFileRoute("/dashboard/reports/group-links")({ + loader: () => getPendingGroupLinkReports(), + pendingComponent: () => , + component: GroupLinkReportsRoute, +}) + +function GroupLinkReportsRoute() { + const reports = Route.useLoaderData() + return +} diff --git a/src/routes/dashboard/reports/resolved.tsx b/src/routes/dashboard/reports/resolved.tsx new file mode 100644 index 0000000..f233ea9 --- /dev/null +++ b/src/routes/dashboard/reports/resolved.tsx @@ -0,0 +1,16 @@ +import { createFileRoute } from "@tanstack/react-router" + +import { DataPageSkeleton } from "@/components/loading-skeleton" +import { GroupLinkReportsPage } from "@/features/group-link-reports/reports-page" +import { getResolvedGroupLinkReports } from "@/features/group-link-reports/reports.functions" + +export const Route = createFileRoute("/dashboard/reports/resolved")({ + loader: () => getResolvedGroupLinkReports(), + pendingComponent: () => , + component: ResolvedGroupLinkReportsRoute, +}) + +function ResolvedGroupLinkReportsRoute() { + const reports = Route.useLoaderData() + return +} diff --git a/src/routes/dashboard/telegram/groups.tsx b/src/routes/dashboard/telegram/groups.tsx index 4208d74..187f094 100644 --- a/src/routes/dashboard/telegram/groups.tsx +++ b/src/routes/dashboard/telegram/groups.tsx @@ -1,4 +1,5 @@ import { createFileRoute } from "@tanstack/react-router" +import { z } from "zod" import { DataPageSkeleton } from "@/components/loading-skeleton" import { listGroupLabels, listGroupsWithLabels } from "@/features/group-labels/group-labels.functions" @@ -6,6 +7,7 @@ import { TelegramGroupsPage } from "@/features/telegram/groups-page" import { getTelegramGroups } from "@/features/telegram/groups.functions" export const Route = createFileRoute("/dashboard/telegram/groups")({ + validateSearch: z.object({ q: z.string().optional() }), loader: async () => { const [groups, groupLabels, groupsWithLabels] = await Promise.all([ getTelegramGroups(), @@ -20,11 +22,13 @@ export const Route = createFileRoute("/dashboard/telegram/groups")({ function TelegramGroupsRoute() { const { groups, groupLabels, groupsWithLabels } = Route.useLoaderData() + const { q } = Route.useSearch() return ( ) } diff --git a/src/routes/dashboard/whatsapp/groups.tsx b/src/routes/dashboard/whatsapp/groups.tsx index 20f2cca..8918d50 100644 --- a/src/routes/dashboard/whatsapp/groups.tsx +++ b/src/routes/dashboard/whatsapp/groups.tsx @@ -1,4 +1,5 @@ import { createFileRoute } from "@tanstack/react-router" +import { z } from "zod" import { DataPageSkeleton } from "@/components/loading-skeleton" import { listGroupLabels, listGroupsWithLabels } from "@/features/group-labels/group-labels.functions" @@ -6,6 +7,7 @@ import { getWhatsappGroups } from "@/features/whatsapp/groups.functions" import { WhatsappGroupsPage } from "@/features/whatsapp/whatsapp-groups-page" export const Route = createFileRoute("/dashboard/whatsapp/groups")({ + validateSearch: z.object({ q: z.string().optional() }), loader: async () => { const [groups, groupLabels, groupsWithLabels] = await Promise.all([ getWhatsappGroups(), @@ -20,11 +22,13 @@ export const Route = createFileRoute("/dashboard/whatsapp/groups")({ function WhatsappGroupsRoute() { const { groups, groupLabels, groupsWithLabels } = Route.useLoaderData() + const { q } = Route.useSearch() return ( ) } From b423a96a2d50e6ff88ad05fcda2462dc9a7b2ef8 Mon Sep 17 00:00:00 2001 From: Bianca Date: Wed, 9 Sep 2026 16:50:16 +0200 Subject: [PATCH 2/3] fix: update dependency version to 1.1.0 --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f8f5976..97f7bac 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "@base-ui/react": "^1.6.0", "@better-auth/passkey": "^1.5.5", "@dnd-kit/react": "^0.4.0", - "@polinetwork/backend": "^0.18.1", + "@polinetwork/backend": "^1.1.0", "@t3-oss/env-core": "^0.13.10", "@tanstack/react-router": "1.170.17", "@tanstack/react-start": "1.168.27", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f7c9cc..81aaea5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,8 +29,8 @@ importers: specifier: ^0.4.0 version: 0.4.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@polinetwork/backend': - specifier: ^0.18.1 - version: 0.18.1 + specifier: ^1.1.0 + version: 1.1.0 '@t3-oss/env-core': specifier: ^0.13.10 version: 0.13.11(typescript@6.0.3)(zod@4.3.5) @@ -1278,8 +1278,8 @@ packages: resolution: {integrity: sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==} engines: {node: ^14.18.0 || >=16.0.0} - '@polinetwork/backend@0.18.1': - resolution: {integrity: sha512-JMH+twKn7WvjX0y7VK5u5FgBLRa1Z651nlR3BRZW/P8xMlNAgLhuin5wP8UWZ6++QdzvMui9XnXEsojuCxt8wg==} + '@polinetwork/backend@1.1.0': + resolution: {integrity: sha512-fc8XwXEODcD9jhENGLaxG1VRJQp91OGnfmMaw1lGR+qiTsNAW1qX9GWdfRoUMxrcZuL4Xx7FU713TlAr4V8dZA==} '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} @@ -6363,7 +6363,7 @@ snapshots: '@pkgr/core@0.3.6': {} - '@polinetwork/backend@0.18.1': {} + '@polinetwork/backend@1.1.0': {} '@polka/url@1.0.0-next.29': {} From 71359d8ffb29b1404d8722a77e2d0e6fb4224bd8 Mon Sep 17 00:00:00 2001 From: Bianca Date: Wed, 9 Sep 2026 16:53:19 +0200 Subject: [PATCH 3/3] refactor: biome --- src/features/group-link-reports/reports-page.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/features/group-link-reports/reports-page.tsx b/src/features/group-link-reports/reports-page.tsx index 3e8e676..cd7b904 100644 --- a/src/features/group-link-reports/reports-page.tsx +++ b/src/features/group-link-reports/reports-page.tsx @@ -63,9 +63,7 @@ function groupReports(reports: GroupLinkReport[]): ReportGroup[] { for (const report of reports) { const key = - report.reportType === "broken_link" - ? `broken_link:${report.type}:${report.groupId}` - : `missing:${report.label}` + report.reportType === "broken_link" ? `broken_link:${report.type}:${report.groupId}` : `missing:${report.label}` const existing = groups.get(key) if (!existing) { @@ -100,9 +98,7 @@ export function GroupLinkReportsPage({ async function handleAction(group: ReportGroup, action: "resolve" | "dismiss") { setPendingKey(group.key) try { - await (action === "resolve" - ? resolve({ data: { ids: group.ids } }) - : dismiss({ data: { ids: group.ids } })) + await (action === "resolve" ? resolve({ data: { ids: group.ids } }) : dismiss({ data: { ids: group.ids } })) await router.invalidate() toast.success(action === "resolve" ? "Report resolved." : "Report dismissed.") } catch (error) { @@ -166,7 +162,9 @@ export function GroupLinkReportsPage({ >
- {report.reportType === "broken_link" ? (report.groupTitle ?? "—") : missingLabel(report)} + + {report.reportType === "broken_link" ? (report.groupTitle ?? "—") : missingLabel(report)} + {group.count > 1 && ( {group.count} @@ -190,7 +188,9 @@ export function GroupLinkReportsPage({ )} - {new Date(report.createdAt).toLocaleDateString()} + + {new Date(report.createdAt).toLocaleDateString()} + {showActions && ( event.stopPropagation()}>