feat: openapi enhancements
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
"@trpc/server": "^11.0.0-rc.566",
|
"@trpc/server": "^11.0.0-rc.566",
|
||||||
"@vercel/postgres": "^0.7.2",
|
"@vercel/postgres": "^0.7.2",
|
||||||
"drizzle-orm": "^0.28.5",
|
"drizzle-orm": "^0.28.5",
|
||||||
"next": "^14.1.3",
|
"next": "^15.0.2",
|
||||||
"nextjs-cors": "^2.2.0",
|
"nextjs-cors": "^2.2.0",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
|||||||
@@ -164,23 +164,25 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateList = ({
|
const updateList = ({
|
||||||
boardId,
|
listPublicId,
|
||||||
listId,
|
|
||||||
currentIndex,
|
currentIndex,
|
||||||
newIndex,
|
newIndex,
|
||||||
}: ReorderListInput) => {
|
}: ReorderListInput) => {
|
||||||
updateListMutation.mutate({
|
updateListMutation.mutate({
|
||||||
boardId,
|
listPublicId,
|
||||||
listId,
|
|
||||||
currentIndex,
|
currentIndex,
|
||||||
newIndex,
|
newIndex,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateCard = ({ cardId, newListId, newIndex }: ReorderCardInput) => {
|
const updateCard = ({
|
||||||
|
cardPublicId,
|
||||||
|
newListPublicId,
|
||||||
|
newIndex,
|
||||||
|
}: ReorderCardInput) => {
|
||||||
updateCardMutation.mutate({
|
updateCardMutation.mutate({
|
||||||
cardId,
|
cardPublicId,
|
||||||
newListId,
|
newListPublicId,
|
||||||
newIndex,
|
newIndex,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,8 +16,12 @@ export const authRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/auth/user",
|
path: "/users/me",
|
||||||
summary: "Get user",
|
summary: "Get user",
|
||||||
|
description:
|
||||||
|
"Retrieves the currently authenticated user's profile information",
|
||||||
|
tags: ["Users"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.void())
|
.input(z.void())
|
||||||
@@ -52,8 +56,10 @@ export const authRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/auth/email",
|
path: "/auth/login/email",
|
||||||
summary: "Login with email",
|
summary: "Login with email",
|
||||||
|
description: "Sends a login URL to the provided email address",
|
||||||
|
tags: ["Auth"],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ email: z.string() }))
|
.input(z.object({ email: z.string() }))
|
||||||
@@ -78,8 +84,11 @@ export const authRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/auth/oauth",
|
path: "/auth/login/oauth",
|
||||||
summary: "Login with OAuth",
|
summary: "Login with OAuth",
|
||||||
|
description:
|
||||||
|
"Initiates the login process for a user with the given OAuth provider",
|
||||||
|
tags: ["Auth"],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ provider: z.string() }))
|
.input(z.object({ provider: z.string() }))
|
||||||
|
|||||||
@@ -13,8 +13,11 @@ export const boardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/board/{workspacePublicId}",
|
path: "/workspaces/{workspacePublicId}/boards",
|
||||||
summary: "Get all boards",
|
summary: "Get all boards",
|
||||||
|
description: "Retrieves all boards for a given workspace",
|
||||||
|
tags: ["Boards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ workspacePublicId: z.string().min(12) }))
|
.input(z.object({ workspacePublicId: z.string().min(12) }))
|
||||||
@@ -41,15 +44,18 @@ export const boardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/board/{boardPublicId}",
|
path: "/boards/{boardPublicId}",
|
||||||
summary: "Get board by public ID",
|
summary: "Get board by public ID",
|
||||||
|
description: "Retrieves a board by its public ID",
|
||||||
|
tags: ["Boards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
boardPublicId: z.string().min(12),
|
boardPublicId: z.string().min(12),
|
||||||
members: z.array(z.string().min(12)),
|
members: z.array(z.string().min(12)).optional(),
|
||||||
labels: z.array(z.string().min(12)),
|
labels: z.array(z.string().min(12)).optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.output(z.custom<Awaited<ReturnType<typeof boardRepo.getByPublicId>>>())
|
.output(z.custom<Awaited<ReturnType<typeof boardRepo.getByPublicId>>>())
|
||||||
@@ -58,8 +64,8 @@ export const boardRouter = createTRPCRouter({
|
|||||||
ctx.db,
|
ctx.db,
|
||||||
input.boardPublicId,
|
input.boardPublicId,
|
||||||
{
|
{
|
||||||
members: input.members,
|
members: input.members ?? [],
|
||||||
labels: input.labels,
|
labels: input.labels ?? [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -69,8 +75,11 @@ export const boardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/board",
|
path: "/workspaces/{workspacePublicId}/boards",
|
||||||
summary: "Create board",
|
summary: "Create board",
|
||||||
|
description: "Creates a new board for a given workspace",
|
||||||
|
tags: ["Boards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -118,8 +127,11 @@ export const boardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
path: "/board/{boardPublicId}",
|
path: "/boards/{boardPublicId}",
|
||||||
summary: "Update board",
|
summary: "Update board",
|
||||||
|
description: "Updates a board by its public ID",
|
||||||
|
tags: ["Boards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -147,8 +159,11 @@ export const boardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
path: "/board/{boardPublicId}",
|
path: "/boards/{boardPublicId}",
|
||||||
summary: "Delete board",
|
summary: "Delete board",
|
||||||
|
description: "Deletes a board by its public ID",
|
||||||
|
tags: ["Boards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ export const cardRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Create a card",
|
summary: "Create a card",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/",
|
path: "/cards",
|
||||||
|
description: "Creates a new card for a given list",
|
||||||
|
tags: ["Cards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -128,8 +131,11 @@ export const cardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
summary: "Add or remove a label from a card",
|
summary: "Add or remove a label from a card",
|
||||||
method: "POST",
|
method: "PUT",
|
||||||
path: "/{cardPublicId}/label/{labelPublicId}",
|
path: "/cards/{cardPublicId}/labels/{labelPublicId}",
|
||||||
|
description: "Adds or removes a label from a card",
|
||||||
|
tags: ["Cards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -184,8 +190,10 @@ export const cardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
summary: "Add or remove a member from a card",
|
summary: "Add or remove a member from a card",
|
||||||
method: "POST",
|
method: "PUT",
|
||||||
path: "/{cardPublicId}/member/{workspaceMemberPublicId}",
|
path: "/cards/{cardPublicId}/members/{workspaceMemberPublicId}",
|
||||||
|
description: "Adds or removes a member from a card",
|
||||||
|
tags: ["Cards"],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -242,12 +250,15 @@ export const cardRouter = createTRPCRouter({
|
|||||||
byId: protectedProcedure
|
byId: protectedProcedure
|
||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
summary: "Get a card by ID",
|
summary: "Get a card by public ID",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/{id}",
|
path: "/cards/{cardPublicId}",
|
||||||
|
description: "Retrieves a card by its public ID",
|
||||||
|
tags: ["Cards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ id: z.string().min(12) }))
|
.input(z.object({ cardPublicId: z.string().min(12) }))
|
||||||
.output(
|
.output(
|
||||||
z.custom<
|
z.custom<
|
||||||
Awaited<ReturnType<typeof cardRepo.getWithListAndMembersByPublicId>>
|
Awaited<ReturnType<typeof cardRepo.getWithListAndMembersByPublicId>>
|
||||||
@@ -256,12 +267,12 @@ export const cardRouter = createTRPCRouter({
|
|||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
const result = await cardRepo.getWithListAndMembersByPublicId(
|
const result = await cardRepo.getWithListAndMembersByPublicId(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
input.id,
|
input.cardPublicId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
message: `Card with ID ${input.id} not found`,
|
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -272,12 +283,15 @@ export const cardRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Update a card",
|
summary: "Update a card",
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
path: "/{cardId}",
|
path: "/cards/{cardPublicId}",
|
||||||
|
description: "Updates a card by its public ID",
|
||||||
|
tags: ["Cards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
cardId: z.string().min(12),
|
cardPublicId: z.string().min(12),
|
||||||
title: z.string().min(1),
|
title: z.string().min(1),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
}),
|
}),
|
||||||
@@ -295,7 +309,7 @@ export const cardRouter = createTRPCRouter({
|
|||||||
const result = await cardRepo.update(
|
const result = await cardRepo.update(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
{ title: input.title, description: input.description },
|
{ title: input.title, description: input.description },
|
||||||
{ cardPublicId: input.cardId },
|
{ cardPublicId: input.cardPublicId },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
@@ -311,7 +325,10 @@ export const cardRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Delete a card",
|
summary: "Delete a card",
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
path: "/{cardPublicId}",
|
path: "/cards/{cardPublicId}",
|
||||||
|
description: "Deletes a card by its public ID",
|
||||||
|
tags: ["Cards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -359,14 +376,17 @@ export const cardRouter = createTRPCRouter({
|
|||||||
.meta({
|
.meta({
|
||||||
openapi: {
|
openapi: {
|
||||||
summary: "Reorder a card",
|
summary: "Reorder a card",
|
||||||
method: "POST",
|
method: "PUT",
|
||||||
path: "/{cardId}/reorder",
|
path: "/cards/{cardPublicId}/reorder",
|
||||||
|
description: "Reorders the position of a card in a given list",
|
||||||
|
tags: ["Cards"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
cardId: z.string().min(12),
|
cardPublicId: z.string().min(12),
|
||||||
newListId: z.string().min(12),
|
newListPublicId: z.string().min(12),
|
||||||
newIndex: z.number().optional(),
|
newIndex: z.number().optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -382,12 +402,12 @@ export const cardRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const card = await cardRepo.getCardWithListByPublicId(
|
const card = await cardRepo.getCardWithListByPublicId(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
input.cardId,
|
input.cardPublicId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!card?.list)
|
if (!card?.list)
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
message: `Card with public ID ${input.cardId} not found`,
|
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -398,12 +418,12 @@ export const cardRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const newList = await listRepo.getWithCardsByPublicId(
|
const newList = await listRepo.getWithCardsByPublicId(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
input.newListId,
|
input.newListPublicId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!newList)
|
if (!newList)
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
message: `List with public ID ${input.newListId} not found`,
|
message: `List with public ID ${input.newListPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ export const importRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Get boards from Trello",
|
summary: "Get boards from Trello",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/boards",
|
path: "/imports/trello/boards",
|
||||||
|
description: "Retrieves all boards from Trello",
|
||||||
|
tags: ["Imports"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -91,7 +94,10 @@ export const importRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Import boards from Trello",
|
summary: "Import boards from Trello",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/import",
|
path: "/imports/trello/import",
|
||||||
|
description: "Imports boards from Trello",
|
||||||
|
tags: ["Imports"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
|
|||||||
@@ -12,17 +12,20 @@ export const labelRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Get a label by public ID",
|
summary: "Get a label by public ID",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/{publicId}",
|
path: "/labels/{labelPublicId}",
|
||||||
|
description: "Retrieves a label by its public ID",
|
||||||
|
tags: ["Labels"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ publicId: z.string().min(12) }))
|
.input(z.object({ labelPublicId: z.string().min(12) }))
|
||||||
.output(z.custom<Awaited<ReturnType<typeof labelRepo.getByPublicId>>>())
|
.output(z.custom<Awaited<ReturnType<typeof labelRepo.getByPublicId>>>())
|
||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
const label = await labelRepo.getByPublicId(ctx.db, input.publicId);
|
const label = await labelRepo.getByPublicId(ctx.db, input.labelPublicId);
|
||||||
|
|
||||||
if (!label)
|
if (!label)
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
message: `Label with public ID ${input.publicId} not found`,
|
message: `Label with public ID ${input.labelPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -33,7 +36,10 @@ export const labelRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Create a label",
|
summary: "Create a label",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/create",
|
path: "/labels",
|
||||||
|
description: "Creates a new label",
|
||||||
|
tags: ["Labels"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -84,12 +90,15 @@ export const labelRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Update a label",
|
summary: "Update a label",
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
path: "/{publicId}",
|
path: "/labels/{labelPublicId}",
|
||||||
|
description: "Updates a label by its public ID",
|
||||||
|
tags: ["Labels"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
publicId: z.string().min(12),
|
labelPublicId: z.string().min(12),
|
||||||
name: z.string().min(1).max(36),
|
name: z.string().min(1).max(36),
|
||||||
colourCode: z.string().length(7),
|
colourCode: z.string().length(7),
|
||||||
}),
|
}),
|
||||||
@@ -105,17 +114,20 @@ export const labelRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Delete a label",
|
summary: "Delete a label",
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
path: "/{publicId}",
|
path: "/labels/{labelPublicId}",
|
||||||
|
description: "Deletes a label by its public ID",
|
||||||
|
tags: ["Labels"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ publicId: z.string().min(12) }))
|
.input(z.object({ labelPublicId: z.string().min(12) }))
|
||||||
.output(z.object({ success: z.boolean() }))
|
.output(z.object({ success: z.boolean() }))
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const label = await labelRepo.getByPublicId(ctx.db, input.publicId);
|
const label = await labelRepo.getByPublicId(ctx.db, input.labelPublicId);
|
||||||
|
|
||||||
if (!label)
|
if (!label)
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
message: `Label with public ID ${input.publicId} not found`,
|
message: `Label with public ID ${input.labelPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ export const listRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Create a list",
|
summary: "Create a list",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/list/create",
|
path: "/lists",
|
||||||
|
description: "Creates a new list for a given board",
|
||||||
|
tags: ["Lists"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -65,24 +68,26 @@ export const listRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Reorder a list",
|
summary: "Reorder a list",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/{listId}/reorder",
|
path: "/lists/{listPublicId}/reorder",
|
||||||
|
description: "Reorders the position of a list",
|
||||||
|
tags: ["Lists"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
boardId: z.string().min(12),
|
listPublicId: z.string().min(12),
|
||||||
listId: z.string().min(12),
|
|
||||||
currentIndex: z.number(),
|
currentIndex: z.number(),
|
||||||
newIndex: z.number(),
|
newIndex: z.number(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.output(z.custom<Awaited<ReturnType<typeof listRepo.reorder>>>())
|
.output(z.custom<Awaited<ReturnType<typeof listRepo.reorder>>>())
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const list = await listRepo.getByPublicId(ctx.db, input.listId);
|
const list = await listRepo.getByPublicId(ctx.db, input.listPublicId);
|
||||||
|
|
||||||
if (!list)
|
if (!list)
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
message: `List with public ID ${input.listId} not found`,
|
message: `List with public ID ${input.listPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,7 +111,10 @@ export const listRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Delete a list",
|
summary: "Delete a list",
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
path: "/{listPublicId}",
|
path: "/lists/{listPublicId}",
|
||||||
|
description: "Deletes a list by its public ID",
|
||||||
|
tags: ["Lists"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -158,7 +166,10 @@ export const listRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Update a list",
|
summary: "Update a list",
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
path: "/list/{listPublicId}",
|
path: "/lists/{listPublicId}",
|
||||||
|
description: "Updates a list by its public ID",
|
||||||
|
tags: ["Lists"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ export const memberRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Invite a member to a workspace",
|
summary: "Invite a member to a workspace",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/invite",
|
path: "/workspaces/{workspacePublicId}/members/invite",
|
||||||
|
description: "Invites a member to a workspace",
|
||||||
|
tags: ["Members"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -144,11 +147,15 @@ export const memberRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Delete a member from a workspace",
|
summary: "Delete a member from a workspace",
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
path: "/{memberPublicId}",
|
path: "/workspaces/{workspacePublicId}/members/{memberPublicId}",
|
||||||
|
description: "Deletes a member from a workspace",
|
||||||
|
tags: ["Members"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
|
workspacePublicId: z.string().min(12),
|
||||||
memberPublicId: z.string().min(12),
|
memberPublicId: z.string().min(12),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -162,6 +169,17 @@ export const memberRouter = createTRPCRouter({
|
|||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const workspace = await workspaceRepo.getByPublicId(
|
||||||
|
ctx.db,
|
||||||
|
input.workspacePublicId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!workspace)
|
||||||
|
throw new TRPCError({
|
||||||
|
message: `Workspace with public ID ${input.workspacePublicId} not found`,
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
});
|
||||||
|
|
||||||
const member = await memberRepo.getByPublicId(
|
const member = await memberRepo.getByPublicId(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
input.memberPublicId,
|
input.memberPublicId,
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Get all workspaces",
|
summary: "Get all workspaces",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/",
|
path: "/workspaces",
|
||||||
|
description: "Retrieves all workspaces for the authenticated user",
|
||||||
|
tags: ["Workspaces"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.void())
|
.input(z.void())
|
||||||
@@ -35,10 +38,13 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Get a workspace by public ID",
|
summary: "Get a workspace by public ID",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/workspace/{publicId}",
|
path: "/workspaces/{workspacePublicId}",
|
||||||
|
description: "Retrieves a workspace by its public ID",
|
||||||
|
tags: ["Workspaces"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ publicId: z.string().min(12) }))
|
.input(z.object({ workspacePublicId: z.string().min(12) }))
|
||||||
.output(
|
.output(
|
||||||
z.custom<
|
z.custom<
|
||||||
Awaited<ReturnType<typeof workspaceRepo.getByPublicIdWithMembers>>
|
Awaited<ReturnType<typeof workspaceRepo.getByPublicIdWithMembers>>
|
||||||
@@ -47,7 +53,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
const result = await workspaceRepo.getByPublicIdWithMembers(
|
const result = await workspaceRepo.getByPublicIdWithMembers(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
input.publicId,
|
input.workspacePublicId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
@@ -63,7 +69,10 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Create a workspace",
|
summary: "Create a workspace",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/workspace/create",
|
path: "/workspaces",
|
||||||
|
description: "Creates a new workspace",
|
||||||
|
tags: ["Workspaces"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -100,7 +109,10 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Update a workspace",
|
summary: "Update a workspace",
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
path: "/workspace/{workspacePublicId}",
|
path: "/workspaces/{workspacePublicId}",
|
||||||
|
description: "Updates a workspace by its public ID",
|
||||||
|
tags: ["Workspaces"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(
|
.input(
|
||||||
@@ -124,7 +136,10 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
openapi: {
|
openapi: {
|
||||||
summary: "Delete a workspace",
|
summary: "Delete a workspace",
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
path: "/workspace/{workspacePublicId}",
|
path: "/workspaces/{workspacePublicId}",
|
||||||
|
description: "Deletes a workspace by its public ID",
|
||||||
|
tags: ["Workspaces"],
|
||||||
|
protect: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.input(z.object({ workspacePublicId: z.string().min(12) }))
|
.input(z.object({ workspacePublicId: z.string().min(12) }))
|
||||||
|
|||||||
@@ -79,16 +79,22 @@ export const createTRPCContext = async ({
|
|||||||
return createInnerTRPCContext({ db, adminDb, user });
|
return createInnerTRPCContext({ db, adminDb, user });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createRESTContext = async ({
|
export const createRESTContext = async ({ req }: CreateNextContextOptions) => {
|
||||||
req,
|
const db = createNextApiClient(req);
|
||||||
res,
|
|
||||||
}: CreateNextContextOptions) => {
|
|
||||||
const db = createNextApiClient(req, res);
|
|
||||||
const adminDb = createTRPCAdminClient();
|
const adminDb = createTRPCAdminClient();
|
||||||
|
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
const accessToken = authHeader?.startsWith("Bearer ")
|
||||||
|
? authHeader.substring(7)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!accessToken) {
|
||||||
|
return createInnerTRPCContext({ db, adminDb, user: null });
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { user },
|
data: { user },
|
||||||
} = await db.auth.getUser();
|
} = await db.auth.getUser(accessToken);
|
||||||
|
|
||||||
return createInnerTRPCContext({ db, adminDb, user });
|
return createInnerTRPCContext({ db, adminDb, user });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -84,14 +84,12 @@ export const getByPublicId = async (
|
|||||||
query = query.in("lists.cards.members.publicId", filters.members);
|
query = query.in("lists.cards.members.publicId", filters.members);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, error } = await query
|
const { data } = await query
|
||||||
.order("index", { foreignTable: "list", ascending: true })
|
.order("index", { foreignTable: "list", ascending: true })
|
||||||
.order("index", { foreignTable: "list.card", ascending: true })
|
.order("index", { foreignTable: "list.card", ascending: true })
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
console.log(error);
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export const getByPublicId = async (
|
|||||||
export const update = async (
|
export const update = async (
|
||||||
db: SupabaseClient<Database>,
|
db: SupabaseClient<Database>,
|
||||||
labelInput: {
|
labelInput: {
|
||||||
publicId: string;
|
labelPublicId: string;
|
||||||
name: string;
|
name: string;
|
||||||
colourCode: string;
|
colourCode: string;
|
||||||
},
|
},
|
||||||
@@ -74,7 +74,7 @@ export const update = async (
|
|||||||
name: labelInput.name,
|
name: labelInput.name,
|
||||||
colourCode: labelInput.colourCode,
|
colourCode: labelInput.colourCode,
|
||||||
})
|
})
|
||||||
.eq("publicId", labelInput.publicId);
|
.eq("publicId", labelInput.labelPublicId);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
import { RequestCookies } from "@edge-runtime/cookies";
|
import { RequestCookies } from "@edge-runtime/cookies";
|
||||||
import { type Database } from "~/types/database.types";
|
import { type Database } from "~/types/database.types";
|
||||||
|
|
||||||
import { type NextApiRequest, type NextApiResponse } from "next";
|
import { type NextApiRequest } from "next";
|
||||||
import { type NextRequest, type NextResponse } from "next/server";
|
import { type NextRequest, type NextResponse } from "next/server";
|
||||||
|
|
||||||
export function createNextClient(req: NextRequest, res: NextResponse) {
|
export function createNextClient(req: NextRequest, res: NextResponse) {
|
||||||
@@ -31,26 +31,25 @@ export function createNextClient(req: NextRequest, res: NextResponse) {
|
|||||||
return supabase;
|
return supabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createNextApiClient(
|
export function createNextApiClient(req: NextApiRequest) {
|
||||||
_req: NextApiRequest,
|
const authHeader = req.headers.authorization;
|
||||||
_res: NextApiResponse,
|
const accessToken = authHeader?.startsWith("Bearer ")
|
||||||
) {
|
? authHeader.substring(7)
|
||||||
|
: null;
|
||||||
|
|
||||||
const supabase = createServerClient<Database>(
|
const supabase = createServerClient<Database>(
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||||
process.env.SUPABASE_SERVICE_API_KEY!,
|
process.env.SUPABASE_SERVICE_API_KEY!,
|
||||||
{
|
{
|
||||||
cookies: {
|
auth: {
|
||||||
get(_name: string) {
|
persistSession: false,
|
||||||
// return req.cookies.get(name)?.value;
|
...(accessToken && {
|
||||||
return "";
|
autoRefreshToken: false,
|
||||||
},
|
detectSessionInUrl: false,
|
||||||
set(_name: string, _value: string, _options: CookieOptions) {
|
access_token: accessToken,
|
||||||
// res.headers.append("Set-Cookie", serialize(name, value, options));
|
}),
|
||||||
},
|
|
||||||
remove(_name: string, _options: CookieOptions) {
|
|
||||||
// res.headers.append("Set-Cookie", serialize(name, "", options));
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
cookies: {},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -104,8 +104,7 @@ export default function BoardPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateList({
|
updateList({
|
||||||
boardId,
|
listPublicId: draggableId,
|
||||||
listId: draggableId,
|
|
||||||
currentIndex: source.index,
|
currentIndex: source.index,
|
||||||
newIndex: destination.index,
|
newIndex: destination.index,
|
||||||
});
|
});
|
||||||
@@ -128,8 +127,8 @@ export default function BoardPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateCard({
|
updateCard({
|
||||||
cardId: draggableId,
|
cardPublicId: draggableId,
|
||||||
newListId: destination.droppableId,
|
newListPublicId: destination.droppableId,
|
||||||
newIndex: destination.index,
|
newIndex: destination.index,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function DeleteLabelConfirmation({
|
|||||||
const { closeModal } = useModal();
|
const { closeModal } = useModal();
|
||||||
const { showPopup } = usePopup();
|
const { showPopup } = usePopup();
|
||||||
|
|
||||||
const refetchCard = () => utils.card.byId.refetch({ id: cardPublicId });
|
const refetchCard = () => utils.card.byId.refetch({ cardPublicId });
|
||||||
|
|
||||||
const deleteLabelMutation = api.label.delete.useMutation({
|
const deleteLabelMutation = api.label.delete.useMutation({
|
||||||
onSuccess: () => refetchCard(),
|
onSuccess: () => refetchCard(),
|
||||||
@@ -29,7 +29,7 @@ export function DeleteLabelConfirmation({
|
|||||||
const handleDeleteLabel = () => {
|
const handleDeleteLabel = () => {
|
||||||
closeModal();
|
closeModal();
|
||||||
deleteLabelMutation.mutate({
|
deleteLabelMutation.mutate({
|
||||||
publicId: labelPublicId,
|
labelPublicId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export function LabelForm({
|
|||||||
|
|
||||||
const label = api.label.byPublicId.useQuery(
|
const label = api.label.byPublicId.useQuery(
|
||||||
{
|
{
|
||||||
publicId: entityId,
|
labelPublicId: entityId,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: isEdit && !!entityId,
|
enabled: isEdit && !!entityId,
|
||||||
@@ -62,7 +62,7 @@ export function LabelForm({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const refetchCard = () => utils.card.byId.refetch({ id: cardPublicId });
|
const refetchCard = () => utils.card.byId.refetch({ cardPublicId });
|
||||||
|
|
||||||
const isCreateAnotherEnabled = watch("isCreateAnotherEnabled");
|
const isCreateAnotherEnabled = watch("isCreateAnotherEnabled");
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ export function LabelForm({
|
|||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
updateLabel.mutate({
|
updateLabel.mutate({
|
||||||
publicId: label.data?.publicId ?? "",
|
labelPublicId: label.data?.publicId ?? "",
|
||||||
name: values.name,
|
name: values.name,
|
||||||
colourCode: values.colour.code,
|
colourCode: values.colour.code,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function LabelSelector({
|
|||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
|
|
||||||
const refetchCard = () => utils.card.byId.refetch({ id: cardPublicId });
|
const refetchCard = () => utils.card.byId.refetch({ cardPublicId });
|
||||||
|
|
||||||
const addOrRemoveLabel = api.card.addOrRemoveLabel.useMutation({
|
const addOrRemoveLabel = api.card.addOrRemoveLabel.useMutation({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default function ListSelector({
|
|||||||
}: ListSelectorProps) {
|
}: ListSelectorProps) {
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
|
|
||||||
const refetchCard = () => utils.card.byId.refetch({ id: cardPublicId });
|
const refetchCard = () => utils.card.byId.refetch({ cardPublicId });
|
||||||
|
|
||||||
const updateCardList = api.card.reorder.useMutation({
|
const updateCardList = api.card.reorder.useMutation({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
@@ -78,8 +78,8 @@ export default function ListSelector({
|
|||||||
setValue(list.publicId, newValue);
|
setValue(list.publicId, newValue);
|
||||||
|
|
||||||
updateCardList.mutate({
|
updateCardList.mutate({
|
||||||
cardId: cardPublicId,
|
cardPublicId,
|
||||||
newListId: list.publicId,
|
newListPublicId: list.publicId,
|
||||||
});
|
});
|
||||||
|
|
||||||
handleSubmit(onSubmit);
|
handleSubmit(onSubmit);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default function MemberSelector({
|
|||||||
}: MemberSelectorProps) {
|
}: MemberSelectorProps) {
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
|
|
||||||
const refetchCard = () => utils.card.byId.refetch({ id: cardPublicId });
|
const refetchCard = () => utils.card.byId.refetch({ cardPublicId });
|
||||||
|
|
||||||
const addOrRemoveMember = api.card.addOrRemoveMember.useMutation({
|
const addOrRemoveMember = api.card.addOrRemoveMember.useMutation({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ export default function CardPage() {
|
|||||||
? params.cardId[0]
|
? params.cardId[0]
|
||||||
: params?.cardId;
|
: params?.cardId;
|
||||||
|
|
||||||
const { data, isLoading } = api.card.byId.useQuery({ id: cardId ?? "" });
|
const { data, isLoading } = api.card.byId.useQuery({
|
||||||
|
cardPublicId: cardId ?? "",
|
||||||
|
});
|
||||||
|
|
||||||
const board = data?.list?.board;
|
const board = data?.list?.board;
|
||||||
const boardId = board?.publicId;
|
const boardId = board?.publicId;
|
||||||
@@ -85,7 +87,7 @@ export default function CardPage() {
|
|||||||
|
|
||||||
const onSubmit = (values: FormValues) => {
|
const onSubmit = (values: FormValues) => {
|
||||||
updateCard.mutate({
|
updateCard.mutate({
|
||||||
cardId: values.cardId,
|
cardPublicId: values.cardId,
|
||||||
title: values.title,
|
title: values.title,
|
||||||
description: values.description,
|
description: values.description,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import { useModal } from "~/providers/modal";
|
import { useModal } from "~/providers/modal";
|
||||||
import { usePopup } from "~/providers/popup";
|
import { usePopup } from "~/providers/popup";
|
||||||
|
import { useWorkspace } from "~/providers/workspace";
|
||||||
|
|
||||||
import Button from "~/components/Button";
|
import Button from "~/components/Button";
|
||||||
|
|
||||||
export function DeleteMemberConfirmation() {
|
export function DeleteMemberConfirmation() {
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
const { closeModal, entityLabel, entityId } = useModal();
|
const { closeModal, entityLabel, entityId } = useModal();
|
||||||
|
const { workspace } = useWorkspace();
|
||||||
const { showPopup } = usePopup();
|
const { showPopup } = usePopup();
|
||||||
|
|
||||||
const deleteMember = api.member.delete.useMutation({
|
const deleteMember = api.member.delete.useMutation({
|
||||||
@@ -31,6 +33,7 @@ export function DeleteMemberConfirmation() {
|
|||||||
if (entityId)
|
if (entityId)
|
||||||
deleteMember.mutate({
|
deleteMember.mutate({
|
||||||
memberPublicId: entityId,
|
memberPublicId: entityId,
|
||||||
|
workspacePublicId: workspace.publicId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function MembersPage() {
|
|||||||
const { workspace } = useWorkspace();
|
const { workspace } = useWorkspace();
|
||||||
|
|
||||||
const { data, isLoading } = api.workspace.byId.useQuery(
|
const { data, isLoading } = api.workspace.byId.useQuery(
|
||||||
{ publicId: workspace.publicId },
|
{ workspacePublicId: workspace.publicId },
|
||||||
// { enabled: workspace?.publicId ? true : false },
|
// { enabled: workspace?.publicId ? true : false },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user