feat: setup card activity

This commit is contained in:
Henry
2024-11-06 22:20:41 +00:00
parent cdaa991098
commit 85b9cfcb21
12 changed files with 2354 additions and 506 deletions

View File

@@ -3,6 +3,7 @@ import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import * as activityRepo from "~/server/db/repository/cardActivity.repo";
import * as boardRepo from "~/server/db/repository/board.repo";
import * as cardRepo from "~/server/db/repository/card.repo";
import * as listRepo from "~/server/db/repository/list.repo";
@@ -203,17 +204,39 @@ export const boardRouter = createTRPCRouter({
});
if (listIds.length) {
await listRepo.softDeleteAllByBoardId(ctx.db, {
const deletedLists = await listRepo.softDeleteAllByBoardId(ctx.db, {
boardId: board.id,
deletedAt,
deletedBy: userId,
});
await cardRepo.softDeleteAllByListIds(ctx.db, {
if (!deletedLists?.length) {
throw new TRPCError({
message: `Failed to delete lists`,
code: "INTERNAL_SERVER_ERROR",
});
}
const deletedCards = await cardRepo.softDeleteAllByListIds(ctx.db, {
listIds,
deletedAt,
deletedBy: userId,
});
if (!deletedCards?.length) {
throw new TRPCError({
message: `Failed to delete cards`,
code: "INTERNAL_SERVER_ERROR",
});
}
const activities = deletedCards.map((card) => ({
type: "card.archived" as const,
createdBy: userId,
cardId: card.id,
}));
await activityRepo.bulkCreate(ctx.db, activities);
}
return { success: true };

View File

@@ -4,6 +4,7 @@ import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import * as cardRepo from "~/server/db/repository/card.repo";
import * as cardActivityRepo from "~/server/db/repository/cardActivity.repo";
import * as labelRepo from "~/server/db/repository/label.repo";
import * as listRepo from "~/server/db/repository/list.repo";
import * as workspaceRepo from "~/server/db/repository/workspace.repo";
@@ -82,6 +83,12 @@ export const cardRouter = createTRPCRouter({
code: "INTERNAL_SERVER_ERROR",
});
await cardActivityRepo.create(ctx.db, {
type: "card.created",
cardId: newCard.id,
createdBy: userId,
});
if (newCardId && input.labelPublicIds.length) {
const labels = await labelRepo.getAllByPublicIds(
ctx.db,
@@ -99,7 +106,25 @@ export const cardRouter = createTRPCRouter({
labelId: label.id,
}));
await cardRepo.bulkCreateCardLabelRelationships(ctx.db, labelsInsert);
const cardLabels = await cardRepo.bulkCreateCardLabelRelationships(
ctx.db,
labelsInsert,
);
if (!cardLabels?.length)
throw new TRPCError({
message: `Failed to create card label relationships`,
code: "INTERNAL_SERVER_ERROR",
});
const cardActivitesInsert = cardLabels.map((cardLabel) => ({
type: "card.updated.label.added" as const,
cardId: cardLabel.cardId,
labelId: cardLabel.labelId,
createdBy: userId,
}));
await cardActivityRepo.bulkCreate(ctx.db, cardActivitesInsert);
}
if (newCardId && input.memberPublicIds.length) {
@@ -119,10 +144,26 @@ export const cardRouter = createTRPCRouter({
workspaceMemberId: member.id,
}));
await cardRepo.bulkCreateCardWorkspaceMemberRelationships(
ctx.db,
membersInsert,
);
const cardMembers =
await cardRepo.bulkCreateCardWorkspaceMemberRelationships(
ctx.db,
membersInsert,
);
if (!cardMembers?.length)
throw new TRPCError({
message: `Failed to create card member relationships`,
code: "INTERNAL_SERVER_ERROR",
});
const cardActivitesInsert = cardMembers.map((cardMember) => ({
type: "card.updated.member.added" as const,
cardId: cardMember.cardId,
workspaceMemberId: cardMember.workspaceMemberId,
createdBy: userId,
}));
await cardActivityRepo.bulkCreate(ctx.db, cardActivitesInsert);
}
return newCard;
@@ -177,12 +218,40 @@ export const cardRouter = createTRPCRouter({
);
if (existingLabel) {
await cardRepo.hardDeleteCardLabelRelationship(ctx.db, cardLabelIds);
const deletedCardLabelRelationship =
await cardRepo.hardDeleteCardLabelRelationship(ctx.db, cardLabelIds);
if (!deletedCardLabelRelationship)
throw new TRPCError({
message: `Failed to remove label from card`,
code: "INTERNAL_SERVER_ERROR",
});
await cardActivityRepo.create(ctx.db, {
type: "card.updated.label.removed" as const,
cardId: card.id,
labelId: label.id,
createdBy: userId,
});
return { newLabel: false };
}
await cardRepo.createCardLabelRelationship(ctx.db, cardLabelIds);
const newCardLabelRelationship =
await cardRepo.createCardLabelRelationship(ctx.db, cardLabelIds);
if (!newCardLabelRelationship)
throw new TRPCError({
message: `Failed to add label to card`,
code: "INTERNAL_SERVER_ERROR",
});
await cardActivityRepo.create(ctx.db, {
type: "card.updated.label.added" as const,
cardId: card.id,
labelId: label.id,
createdBy: userId,
});
return { newLabel: true };
}),
@@ -238,12 +307,43 @@ export const cardRouter = createTRPCRouter({
);
if (existingMember) {
await cardRepo.hardDeleteCardMemberRelationship(ctx.db, cardMemberIds);
const deletedCardMemberRelationship =
await cardRepo.hardDeleteCardMemberRelationship(
ctx.db,
cardMemberIds,
);
if (!deletedCardMemberRelationship?.success)
throw new TRPCError({
message: `Failed to remove member from card`,
code: "INTERNAL_SERVER_ERROR",
});
await cardActivityRepo.create(ctx.db, {
type: "card.updated.member.removed" as const,
cardId: card.id,
workspaceMemberId: member.id,
createdBy: userId,
});
return { newMember: false };
}
await cardRepo.createCardMemberRelationship(ctx.db, cardMemberIds);
const newCardMemberRelationship =
await cardRepo.createCardMemberRelationship(ctx.db, cardMemberIds);
if (!newCardMemberRelationship?.success)
throw new TRPCError({
message: `Failed to add member to card`,
code: "INTERNAL_SERVER_ERROR",
});
await cardActivityRepo.create(ctx.db, {
type: "card.updated.member.added" as const,
cardId: card.id,
workspaceMemberId: member.id,
createdBy: userId,
});
return { newMember: true };
}),
@@ -306,6 +406,18 @@ export const cardRouter = createTRPCRouter({
code: "UNAUTHORIZED",
});
const existingCard = await cardRepo.getByPublicId(
ctx.db,
input.cardPublicId,
);
if (!existingCard) {
throw new TRPCError({
message: `Card with public ID ${input.cardPublicId} not found`,
code: "NOT_FOUND",
});
}
const result = await cardRepo.update(
ctx.db,
{ title: input.title, description: input.description },
@@ -318,6 +430,32 @@ export const cardRouter = createTRPCRouter({
code: "INTERNAL_SERVER_ERROR",
});
const activities = [];
if (existingCard.title !== input.title) {
activities.push({
type: "card.updated.title" as const,
cardId: result.id,
createdBy: userId,
fromTitle: existingCard.title,
toTitle: input.title,
});
}
if (existingCard.description !== input.description) {
activities.push({
type: "card.updated.description" as const,
cardId: result.id,
createdBy: userId,
fromDescription: existingCard.description ?? undefined,
toDescription: input.description,
});
}
if (activities.length > 0) {
await cardActivityRepo.bulkCreate(ctx.db, activities);
}
return result;
}),
delete: protectedProcedure
@@ -359,17 +497,29 @@ export const cardRouter = createTRPCRouter({
const deletedAt = new Date().toISOString();
await cardRepo.softDelete(ctx.db, {
const deletedCard = await cardRepo.softDelete(ctx.db, {
cardId: card.id,
deletedAt,
deletedBy: userId,
});
if (!deletedCard)
throw new TRPCError({
message: `Failed to delete card`,
code: "INTERNAL_SERVER_ERROR",
});
await cardRepo.shiftIndex(ctx.db, {
listId: card.list.id,
cardIndex: card.index,
});
await cardActivityRepo.create(ctx.db, {
type: "card.archived",
cardId: card.id,
createdBy: userId,
});
return { success: true };
}),
reorder: protectedProcedure
@@ -435,7 +585,7 @@ export const cardRouter = createTRPCRouter({
newIndex = lastCardIndex !== undefined ? lastCardIndex + 1 : 0;
}
const result = await cardRepo.reorder(ctx.db, {
const { success } = await cardRepo.reorder(ctx.db, {
currentListId: currentList.id,
newListId: newList.id,
currentIndex,
@@ -443,6 +593,38 @@ export const cardRouter = createTRPCRouter({
cardId: card.id,
});
return { success: !!result.error };
if (!success)
throw new TRPCError({
message: `Failed to reorder card`,
code: "INTERNAL_SERVER_ERROR",
});
const activities = [];
if (currentIndex !== newIndex) {
activities.push({
type: "card.updated.index" as const,
cardId: card.id,
createdBy: userId,
fromIndex: currentIndex,
toIndex: newIndex,
});
}
if (currentList.id !== newList.id) {
activities.push({
type: "card.updated.list" as const,
cardId: card.id,
createdBy: userId,
fromListId: currentList.id,
toListId: newList.id,
});
}
if (activities.length > 0) {
await cardActivityRepo.bulkCreate(ctx.db, activities);
}
return { success };
}),
});

View File

@@ -5,6 +5,7 @@ import { generateUID } from "~/utils/generateUID";
import * as boardRepo from "~/server/db/repository/board.repo";
import * as cardRepo from "~/server/db/repository/card.repo";
import * as cardActivityRepo from "~/server/db/repository/cardActivity.repo";
import * as importRepo from "~/server/db/repository/import.repo";
import * as listRepo from "~/server/db/repository/list.repo";
import * as workspaceRepo from "~/server/db/repository/workspace.repo";
@@ -196,9 +197,26 @@ export const importRouter = createTRPCRouter({
importId: newImportId,
}));
await cardRepo.bulkCreate(ctx.db, cardsInsert);
const createdCards = await cardRepo.bulkCreate(
ctx.db,
cardsInsert,
);
await ctx.db.from("card").insert(cardsInsert);
if (!createdCards?.length)
throw new TRPCError({
message: "Failed to create new cards",
code: "INTERNAL_SERVER_ERROR",
});
const activities = createdCards.map((card) => ({
type: "card.created" as const,
cardId: card.id,
createdBy: userId,
}));
if (createdCards.length > 0) {
await cardActivityRepo.bulkCreate(ctx.db, activities);
}
}
listIndex++;

View File

@@ -3,6 +3,7 @@ import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import * as activityRepo from "~/server/db/repository/cardActivity.repo";
import * as cardRepo from "~/server/db/repository/card.repo";
import * as boardRepo from "~/server/db/repository/board.repo";
import * as listRepo from "~/server/db/repository/list.repo";
@@ -142,18 +143,38 @@ export const listRouter = createTRPCRouter({
const deletedAt = new Date().toISOString();
await listRepo.softDeleteById(ctx.db, {
const deletedList = await listRepo.softDeleteById(ctx.db, {
listId: list.id,
deletedAt,
deletedBy: userId,
});
await cardRepo.softDeleteAllByListIds(ctx.db, {
if (!deletedList)
throw new TRPCError({
message: `Failed to delete list`,
code: "INTERNAL_SERVER_ERROR",
});
const deletedCards = await cardRepo.softDeleteAllByListIds(ctx.db, {
listIds: [list.id],
deletedAt,
deletedBy: userId,
});
if (!deletedCards?.length)
throw new TRPCError({
message: `Failed to delete cards`,
code: "INTERNAL_SERVER_ERROR",
});
const activities = deletedCards.map((card) => ({
type: "card.archived" as const,
createdBy: userId,
cardId: card.id,
}));
await activityRepo.bulkCreate(ctx.db, activities);
await listRepo.shiftIndex(ctx.db, {
boardId: list.boardId,
listIndex: list.id,

View File

@@ -0,0 +1,55 @@
DO $$ BEGIN
CREATE TYPE "card_activity_type" AS ENUM('card.created', 'card.updated.title', 'card.updated.description', 'card.updated.index', 'card.updated.list', 'card.updated.label.added', 'card.updated.label.removed', 'card.updated.member.added', 'card.updated.member.removed', 'card.archived');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "card_activity" (
"id" bigserial PRIMARY KEY NOT NULL,
"publicId" varchar(12) NOT NULL,
"type" "card_activity_type" NOT NULL,
"cardId" bigint NOT NULL,
"fromIndex" integer,
"toIndex" integer,
"fromListId" bigint,
"toListId" bigint,
"labelId" bigint,
"workspaceMemberId" bigint,
"fromTitle" varchar(255),
"toTitle" varchar(255),
"fromDescription" text,
"toDescription" text,
"createdBy" uuid NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
CONSTRAINT "card_activity_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "card"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_toListId_list_id_fk" FOREIGN KEY ("toListId") REFERENCES "list"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_labelId_label_id_fk" FOREIGN KEY ("labelId") REFERENCES "label"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_workspaceMemberId_workspace_members_id_fk" FOREIGN KEY ("workspaceMemberId") REFERENCES "workspace_members"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,13 @@
"when": 1730205607613,
"tag": "0004_rainy_archangel",
"breakpoints": true
},
{
"idx": 5,
"version": "5",
"when": 1730813108528,
"tag": "0005_blue_marvex",
"breakpoints": true
}
]
}

View File

@@ -36,9 +36,12 @@ export const bulkCreateCardLabelRelationships = async (
labelId: number;
}[],
) => {
const result = db.from("_card_labels").insert(cardLabelRelationshipInput);
const { data } = await db
.from("_card_labels")
.insert(cardLabelRelationshipInput)
.select();
return result;
return data;
};
export const bulkCreateCardWorkspaceMemberRelationships = async (
@@ -48,11 +51,12 @@ export const bulkCreateCardWorkspaceMemberRelationships = async (
workspaceMemberId: number;
}[],
) => {
const result = db
const { data } = await db
.from("_card_workspace_members")
.insert(cardWorkspaceMemberRelationshipInput);
.insert(cardWorkspaceMemberRelationshipInput)
.select();
return result;
return data;
};
export const update = async (
@@ -69,7 +73,11 @@ export const update = async (
.from("card")
.update({ title: cardInput.title, description: cardInput.description })
.eq("publicId", args.cardPublicId)
.is("deletedAt", null);
.is("deletedAt", null)
.select(`id, publicId, title, description`)
.order("id", { ascending: true })
.limit(1)
.single();
return data;
};
@@ -95,7 +103,7 @@ export const getByPublicId = async (
) => {
const { data } = await db
.from("card")
.select(`id`)
.select(`id, publicId, title, description`)
.eq("publicId", cardPublicId)
.limit(1)
.single();
@@ -130,7 +138,7 @@ export const bulkCreate = async (
importId?: number;
}[],
) => {
const data = await db.from("card").insert(cardInput);
const { data } = await db.from("card").insert(cardInput).select(`id`);
return data;
};
@@ -139,10 +147,15 @@ export const createCardLabelRelationship = async (
db: SupabaseClient<Database>,
cardLabelRelationshipInput: { cardId: number; labelId: number },
) => {
const { data } = await db.from("_card_labels").insert({
cardId: cardLabelRelationshipInput.cardId,
labelId: cardLabelRelationshipInput.labelId,
});
const { data } = await db
.from("_card_labels")
.insert({
cardId: cardLabelRelationshipInput.cardId,
labelId: cardLabelRelationshipInput.labelId,
})
.select()
.limit(1)
.single();
return data;
};
@@ -166,12 +179,12 @@ export const createCardMemberRelationship = async (
db: SupabaseClient<Database>,
cardMemberRelationshipInput: { cardId: number; memberId: number },
) => {
const { data } = await db.from("_card_workspace_members").insert({
const { error } = await db.from("_card_workspace_members").insert({
cardId: cardMemberRelationshipInput.cardId,
workspaceMemberId: cardMemberRelationshipInput.memberId,
});
return data;
return { success: !error };
};
export const getWithListAndMembersByPublicId = async (
@@ -247,7 +260,7 @@ export const reorder = async (
cardId: number;
},
) => {
const result = await db.rpc("reorder_cards", {
const { error } = await db.rpc("reorder_cards", {
current_list_id: args.currentListId,
new_list_id: args.newListId,
current_index: args.currentIndex,
@@ -255,7 +268,7 @@ export const reorder = async (
card_id: args.cardId,
});
return result;
return { success: !error };
};
export const shiftIndex = async (
@@ -296,12 +309,16 @@ export const softDelete = async (
deletedBy: string;
},
) => {
const result = await db
const { data } = await db
.from("card")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("id", args.cardId);
.eq("id", args.cardId)
.select(`id`)
.order("id", { ascending: true })
.limit(1)
.single();
return result;
return data;
};
export const softDeleteAllByListIds = async (
@@ -312,39 +329,46 @@ export const softDeleteAllByListIds = async (
deletedBy: string;
},
) => {
const result = await db
const { data } = await db
.from("card")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.in("listId", args.listIds)
.is("deletedAt", null);
.is("deletedAt", null)
.select(`id`);
return result;
return data;
};
export const hardDeleteCardMemberRelationship = async (
db: SupabaseClient<Database>,
args: { cardId: number; memberId: number },
) => {
const result = await db
const { error } = await db
.from("_card_workspace_members")
.delete()
.eq("cardId", args.cardId)
.eq("workspaceMemberId", args.memberId);
.eq("workspaceMemberId", args.memberId)
.select()
.limit(1)
.single();
return result;
return { success: !error };
};
export const hardDeleteCardLabelRelationship = async (
db: SupabaseClient<Database>,
args: { cardId: number; labelId: number },
) => {
const result = await db
const { data } = await db
.from("_card_labels")
.delete()
.eq("cardId", args.cardId)
.eq("labelId", args.labelId);
.eq("labelId", args.labelId)
.select()
.limit(1)
.single();
return result;
return { data };
};
export const hardDeleteAllCardLabelRelationships = async (

View File

@@ -0,0 +1,77 @@
import { generateUID } from "~/utils/generateUID";
import { type Database } from "~/types/database.types";
import { type SupabaseClient } from "@supabase/supabase-js";
export const create = async (
db: SupabaseClient<Database>,
activityInput: {
type: Database["public"]["Enums"]["card_activity_type"];
cardId: number;
fromIndex?: number;
toIndex?: number;
fromListId?: number;
toListId?: number;
labelId?: number;
workspaceMemberId?: number;
fromTitle?: string;
toTitle?: string;
fromDescription?: string;
toDescription?: string;
createdBy: string;
},
) => {
const { data } = await db
.from("card_activity")
.insert({
publicId: generateUID(),
type: activityInput.type,
cardId: activityInput.cardId,
fromListId: activityInput.fromListId,
toListId: activityInput.toListId,
fromIndex: activityInput.fromIndex,
toIndex: activityInput.toIndex,
labelId: activityInput.labelId,
workspaceMemberId: activityInput.workspaceMemberId,
fromTitle: activityInput.fromTitle,
toTitle: activityInput.toTitle,
fromDescription: activityInput.fromDescription,
toDescription: activityInput.toDescription,
createdBy: activityInput.createdBy,
})
.select(`id`)
.limit(1)
.single();
return data;
};
export const bulkCreate = async (
db: SupabaseClient<Database>,
activityInputs: {
type: Database["public"]["Enums"]["card_activity_type"];
cardId: number;
fromIndex?: number;
toIndex?: number;
fromListId?: number;
toListId?: number;
labelId?: number;
workspaceMemberId?: number;
fromTitle?: string;
toTitle?: string;
fromDescription?: string;
toDescription?: string;
createdBy: string;
}[],
) => {
const activitiesWithPublicIds = activityInputs.map((activity) => ({
...activity,
publicId: generateUID(),
}));
const { data } = await db
.from("card_activity")
.insert(activitiesWithPublicIds)
.select("id");
return data;
};

View File

@@ -127,13 +127,15 @@ export const softDeleteAllByBoardId = async (
deletedBy: string;
},
) => {
const result = await db
const { data } = await db
.from("list")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("boardId", args.boardId)
.is("deletedAt", null);
.is("deletedAt", null)
.select(`id`)
.order("id", { ascending: true });
return result;
return data;
};
export const softDeleteById = async (
@@ -144,11 +146,15 @@ export const softDeleteById = async (
deletedBy: string;
},
) => {
const result = await db
const { data } = await db
.from("list")
.update({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
.eq("id", args.listId)
.is("deletedAt", null);
.is("deletedAt", null)
.select(`id`)
.order("id", { ascending: true })
.limit(1)
.single();
return result;
return data;
};

View File

@@ -24,6 +24,18 @@ export const memberStatusEnum = pgEnum("member_status", [
"active",
"removed",
]);
export const activityTypeEnum = pgEnum("card_activity_type", [
"card.created",
"card.updated.title",
"card.updated.description",
"card.updated.index",
"card.updated.list",
"card.updated.label.added",
"card.updated.label.removed",
"card.updated.member.added",
"card.updated.member.removed",
"card.archived",
]);
export const boards = pgTable("board", {
id: bigserial("id", { mode: "number" }).primaryKey(),
@@ -324,3 +336,55 @@ export const usersToWorkspacesRelations = relations(
}),
}),
);
export const cardActivities = pgTable("card_activity", {
id: bigserial("id", { mode: "number" }).primaryKey(),
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
type: activityTypeEnum("type").notNull(),
cardId: bigint("cardId", { mode: "number" })
.notNull()
.references(() => cards.id, { onDelete: "cascade" }),
fromIndex: integer("fromIndex"),
toIndex: integer("toIndex"),
fromListId: bigint("fromListId", { mode: "number" }),
toListId: bigint("toListId", { mode: "number" }).references(() => lists.id),
labelId: bigint("labelId", { mode: "number" }).references(() => labels.id),
workspaceMemberId: bigint("workspaceMemberId", { mode: "number" }).references(
() => workspaceMembers.id,
),
fromTitle: varchar("fromTitle", { length: 255 }),
toTitle: varchar("toTitle", { length: 255 }),
fromDescription: text("fromDescription"),
toDescription: text("toDescription"),
createdBy: uuid("createdBy")
.notNull()
.references(() => users.id),
createdAt: timestamp("createdAt").defaultNow().notNull(),
});
export const cardActivitiesRelations = relations(cardActivities, ({ one }) => ({
card: one(cards, {
fields: [cardActivities.cardId],
references: [cards.id],
}),
fromList: one(lists, {
fields: [cardActivities.fromListId],
references: [lists.id],
}),
toList: one(lists, {
fields: [cardActivities.toListId],
references: [lists.id],
}),
label: one(labels, {
fields: [cardActivities.labelId],
references: [labels.id],
}),
workspaceMember: one(workspaceMembers, {
fields: [cardActivities.workspaceMemberId],
references: [workspaceMembers.id],
}),
createdBy: one(users, {
fields: [cardActivities.createdBy],
references: [users.id],
}),
}));

File diff suppressed because it is too large Load Diff