fix: logs api should with both API and access keys

This commit is contained in:
Harshith Mullapudi 2025-09-22 19:57:11 +05:30
parent 169a2713d2
commit b912080815
2 changed files with 134 additions and 127 deletions

View File

@ -47,7 +47,7 @@ export function useLogs({ endpoint, source, status, type }: UseLogsOptions) {
(pageNum: number) => { (pageNum: number) => {
const params = new URLSearchParams(); const params = new URLSearchParams();
params.set("page", pageNum.toString()); params.set("page", pageNum.toString());
params.set("limit", "5"); params.set("limit", "50");
if (source) params.set("source", source); if (source) params.set("source", source);
if (status) params.set("status", status); if (status) params.set("status", status);
if (type) params.set("type", type); if (type) params.set("type", type);

View File

@ -1,150 +1,157 @@
import { type LoaderFunctionArgs, json } from "@remix-run/node"; import { type LoaderFunctionArgs, json } from "@remix-run/node";
import { z } from "zod";
import { prisma } from "~/db.server"; import { prisma } from "~/db.server";
import { requireUserId } from "~/services/session.server"; import { createHybridLoaderApiRoute } from "~/services/routeBuilders/apiBuilder.server";
/** // Schema for logs search parameters
* Optimizations: const LogsSearchParams = z.object({
* - Use `findMany` with `select` instead of `include` to fetch only required fields. page: z.string().optional(),
* - Use `count` with the same where clause, but only after fetching logs (to avoid unnecessary count if no logs). limit: z.string().optional(),
* - Use a single query for availableSources with minimal fields. source: z.string().optional(),
* - Avoid unnecessary object spreading and type casting. status: z.string().optional(),
* - Minimize nested object traversal in mapping. type: z.string().optional(),
*/ });
export async function loader({ request }: LoaderFunctionArgs) {
const userId = await requireUserId(request);
const url = new URL(request.url);
const page = parseInt(url.searchParams.get("page") || "1"); export const loader = createHybridLoaderApiRoute(
const limit = parseInt(url.searchParams.get("limit") || "100"); {
const source = url.searchParams.get("source"); allowJWT: true,
const status = url.searchParams.get("status"); searchParams: LogsSearchParams,
const type = url.searchParams.get("type"); corsStrategy: "all",
const skip = (page - 1) * limit; findResource: async () => 1,
},
async ({ authentication, searchParams }) => {
const page = parseInt(searchParams.page || "1");
const limit = parseInt(searchParams.limit || "100");
const source = searchParams.source;
const status = searchParams.status;
const type = searchParams.type;
const skip = (page - 1) * limit;
// Get user and workspace in one query // Get user and workspace in one query
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({
where: { id: userId }, where: { id: authentication.userId },
select: { Workspace: { select: { id: true } } }, select: { Workspace: { select: { id: true } } },
}); });
if (!user?.Workspace) { if (!user?.Workspace) {
throw new Response("Workspace not found", { status: 404 }); throw new Response("Workspace not found", { status: 404 });
} }
// Build where clause for filtering // Build where clause for filtering
const whereClause: any = { const whereClause: any = {
workspaceId: user.Workspace.id, workspaceId: user.Workspace.id,
};
if (status) {
whereClause.status = status;
}
if (type) {
whereClause.data = {
path: ["type"],
equals: type,
}; };
}
// If source filter is provided, filter by integration source if (status) {
if (source) { whereClause.status = status;
whereClause.activity = { }
integrationAccount: {
integrationDefinition: { if (type) {
slug: source, whereClause.data = {
path: ["type"],
equals: type,
};
}
// If source filter is provided, filter by integration source
if (source) {
whereClause.activity = {
integrationAccount: {
integrationDefinition: {
slug: source,
},
}, },
}, };
}; }
}
// Use select to fetch only required fields for logs // Use select to fetch only required fields for logs
const [logs, totalCount, availableSources] = await Promise.all([ const [logs, totalCount, availableSources] = await Promise.all([
prisma.ingestionQueue.findMany({ prisma.ingestionQueue.findMany({
where: whereClause, where: whereClause,
select: { select: {
id: true, id: true,
createdAt: true, createdAt: true,
processedAt: true, processedAt: true,
status: true, status: true,
error: true, error: true,
type: true, type: true,
output: true, output: true,
data: true, data: true,
activity: { activity: {
select: { select: {
text: true, text: true,
sourceURL: true, sourceURL: true,
integrationAccount: { integrationAccount: {
select: { select: {
integrationDefinition: { integrationDefinition: {
select: { select: {
name: true, name: true,
slug: true, slug: true,
},
}, },
}, },
}, },
}, },
}, },
}, },
}, orderBy: {
orderBy: { createdAt: "desc",
createdAt: "desc", },
}, skip,
skip, take: limit,
take: limit, }),
}),
prisma.ingestionQueue.count({ prisma.ingestionQueue.count({
where: whereClause, where: whereClause,
}), }),
prisma.integrationDefinitionV2.findMany({ prisma.integrationDefinitionV2.findMany({
where: { where: {
IntegrationAccount: { IntegrationAccount: {
some: { some: {
workspaceId: user.Workspace.id, workspaceId: user.Workspace.id,
},
}, },
}, },
}, select: {
select: { name: true,
name: true, slug: true,
slug: true, },
}, }),
}), ]);
]);
// Format the response // Format the response
const formattedLogs = logs.map((log) => { const formattedLogs = logs.map((log) => {
const integrationDef = const integrationDef =
log.activity?.integrationAccount?.integrationDefinition; log.activity?.integrationAccount?.integrationDefinition;
const logData = log.data as any; const logData = log.data as any;
return { return {
id: log.id, id: log.id,
source: integrationDef?.name || logData?.source || "Unknown", source: integrationDef?.name || logData?.source || "Unknown",
ingestText: ingestText:
log.activity?.text || log.activity?.text ||
logData?.episodeBody || logData?.episodeBody ||
logData?.text || logData?.text ||
"No content", "No content",
time: log.createdAt, time: log.createdAt,
processedAt: log.processedAt, processedAt: log.processedAt,
episodeUUID: (log.output as any)?.episodeUuid, episodeUUID: (log.output as any)?.episodeUuid,
status: log.status, status: log.status,
error: log.error, error: log.error,
sourceURL: log.activity?.sourceURL, sourceURL: log.activity?.sourceURL,
integrationSlug: integrationDef?.slug, integrationSlug: integrationDef?.slug,
data: log.data, data: log.data,
}; };
}); });
return json({ return json({
logs: formattedLogs, logs: formattedLogs,
totalCount, totalCount,
page, page,
limit, limit,
hasMore: skip + logs.length < totalCount, hasMore: skip + logs.length < totalCount,
availableSources, availableSources,
}); });
} },
);