feat: paginate and merge frequent activities (#274)
* feat: paginate and merge frequent activities * feat: due date activities * fix: requested changes fixes * refactor: slight reshuffle and improve types * chore: translations --------- Co-authored-by: Henry <henry_ball@hotmail.co.uk>
This commit is contained in:
@@ -9,6 +9,7 @@ import * as listRepo from "@kan/db/repository/list.repo";
|
||||
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||
import { mergeActivities } from "../utils/activities";
|
||||
import { assertUserInWorkspace } from "../utils/auth";
|
||||
import { generateDownloadUrl } from "../utils/s3";
|
||||
|
||||
@@ -670,6 +671,81 @@ export const cardRouter = createTRPCRouter({
|
||||
|
||||
return { ...result, attachments: [] };
|
||||
}),
|
||||
getActivities: publicProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Get paginated card activities",
|
||||
method: "GET",
|
||||
path: "/cards/{cardPublicId}/activities",
|
||||
description:
|
||||
"Retrieves paginated activities for a card with merged frequent changes",
|
||||
tags: ["Cards"],
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
cardPublicId: z.string().min(12),
|
||||
limit: z.number().min(1).max(100).optional().default(10),
|
||||
cursor: z.string().datetime().optional(), // ISO datetime string
|
||||
}),
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
activities: z.array(
|
||||
z.custom<
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<typeof cardActivityRepo.getPaginatedActivities>
|
||||
>
|
||||
>["activities"][number]
|
||||
>(),
|
||||
),
|
||||
hasMore: z.boolean(),
|
||||
nextCursor: z.string().datetime().nullable(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const card = await cardRepo.getWorkspaceAndCardIdByCardPublicId(
|
||||
ctx.db,
|
||||
input.cardPublicId,
|
||||
);
|
||||
|
||||
if (!card)
|
||||
throw new TRPCError({
|
||||
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
if (card.workspaceVisibility === "private") {
|
||||
const userId = ctx.user?.id;
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
}
|
||||
|
||||
const cursor = input.cursor ? new Date(input.cursor) : undefined;
|
||||
const result = await cardActivityRepo.getPaginatedActivities(
|
||||
ctx.db,
|
||||
card.id,
|
||||
{
|
||||
limit: input.limit,
|
||||
cursor,
|
||||
},
|
||||
);
|
||||
|
||||
const mergedActivities = mergeActivities(result.activities);
|
||||
|
||||
return {
|
||||
activities: mergedActivities,
|
||||
hasMore: result.hasMore,
|
||||
nextCursor: result.nextCursor?.toISOString() ?? null,
|
||||
};
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
|
||||
Reference in New Issue
Block a user