fix(platform+admin-web): 3 bugs in delivery retry + webhooks delivery loading

Backend (delivery retry):
- Use NotFoundError (404) instead of BadRequestError (400) for missing log doc
- Add telegram + slack retry support (was email-only, threw error for others)

Frontend (delivery page):
- Add pk field to DeliveryEntry interface
- Pass pk query param in retry call so backend can look up the doc
- Fix handleRetry to accept full entry object instead of just id

Frontend (webhooks page):
- Parallelize delivery fetches with Promise.allSettled (was sequential for loop)
- Significant page load improvement for subscriptions with many deliveries
This commit is contained in:
saravanakumardb1 2026-03-21 23:21:58 -07:00
parent f92504ceb4
commit 9180954903
3 changed files with 44 additions and 20 deletions

View File

@ -24,6 +24,7 @@ import {
interface DeliveryEntry {
id: string;
pk: string;
template: string;
recipient: string;
channel: string;
@ -71,8 +72,10 @@ export default function DeliveryPage() {
void loadData();
}, [loadData]);
async function handleRetry(id: string) {
await apiFetch(`logs/${id}/retry`, { method: 'POST' });
async function handleRetry(entry: DeliveryEntry) {
await apiFetch(`logs/${entry.id}/retry?pk=${encodeURIComponent(entry.pk)}`, {
method: 'POST',
});
loadData();
}
@ -191,7 +194,7 @@ export default function DeliveryPage() {
<TableCell>
{e.status === 'failed' && (
<button
onClick={() => handleRetry(e.id)}
onClick={() => handleRetry(e)}
className="text-xs text-blue-600 hover:underline"
>
Retry

View File

@ -81,21 +81,22 @@ export default function WebhooksPage() {
: [];
setSubs(subsList);
// Load deliveries per-subscription (backend only has GET /webhooks/subscriptions/:id/deliveries)
const allDeliveries: Delivery[] = [];
for (const sub of subsList.slice(0, 10)) {
try {
const dData = await apiFetch(`subscriptions/${sub.id}/deliveries`);
const items: Delivery[] = Array.isArray(dData?.deliveries)
? dData.deliveries
: Array.isArray(dData)
? dData
: [];
allDeliveries.push(...items);
} catch {
// best-effort
}
}
// Load deliveries per-subscription in parallel (backend only has per-sub endpoint)
const results = await Promise.allSettled(
subsList.slice(0, 10).map(sub =>
apiFetch(`subscriptions/${sub.id}/deliveries`).then((dData: Record<string, unknown>) => {
const items: Delivery[] = Array.isArray(dData?.deliveries)
? (dData.deliveries as Delivery[])
: Array.isArray(dData)
? (dData as unknown as Delivery[])
: [];
return items;
})
)
);
const allDeliveries = results
.filter((r): r is PromiseFulfilledResult<Delivery[]> => r.status === 'fulfilled')
.flatMap(r => r.value);
setDeliveries(allDeliveries.sort((a, b) => b.createdAt.localeCompare(a.createdAt)));
setLoading(false);
}, []);

View File

@ -1,6 +1,6 @@
import type { FastifyInstance } from 'fastify';
import { extractAuth } from '../../lib/auth.js';
import { BadRequestError } from '../../lib/errors.js';
import { BadRequestError, NotFoundError } from '../../lib/errors.js';
import {
SendEmailSchema,
SendSlackSchema,
@ -130,7 +130,7 @@ export async function deliveryRoutes(app: FastifyInstance) {
// Look up the original log entry
const original = await repo.getDeliveryLog(id, pk);
if (!original) throw new BadRequestError(`Delivery log '${id}' not found`);
if (!original) throw new NotFoundError(`Delivery log '${id}' not found`);
if (original.status !== 'failed') {
throw new BadRequestError(
`Can only retry failed deliveries (current status: ${original.status})`
@ -152,6 +152,26 @@ export async function deliveryRoutes(app: FastifyInstance) {
return { success: result.success, messageId: result.messageId, error: result.error };
}
if (original.channel === 'telegram') {
const result = await dispatchTelegram({
text: (original.metadata as Record<string, string>)?.text ?? original.subject ?? '',
productId: original.productId,
chatId: original.to,
userId: original.userId,
});
return { success: result.success, messageId: result.messageId, error: result.error };
}
if (original.channel === 'slack') {
const result = await dispatchSlack({
text: (original.metadata as Record<string, string>)?.text ?? original.subject ?? '',
productId: original.productId,
channel: original.to,
userId: original.userId,
});
return { success: result.success, messageId: result.messageId, error: result.error };
}
throw new BadRequestError(`Retry not supported for channel '${original.channel}'`);
});