Compare commits

..

1 Commits

Author SHA1 Message Date
Henry
4c7252610f fix: prevent member dropdown from being cutoff 2025-07-26 21:31:19 +01:00
4 changed files with 33 additions and 49 deletions

View File

@@ -167,8 +167,7 @@ export function UpdateBoardSlugForm({
!isDirty || !isDirty ||
updateBoardSlug.isPending || updateBoardSlug.isPending ||
errors.slug?.message !== undefined || errors.slug?.message !== undefined ||
isBoardSlugAvailable?.isReserved || isBoardSlugAvailable?.isReserved
checkBoardSlugAvailability.isLoading
} }
> >
{t`Update`} {t`Update`}

View File

@@ -97,7 +97,7 @@ export default function MembersPage() {
</td> </td>
<td <td
className={twMerge( className={twMerge(
"w-auto min-w-[120px] sm:w-[35%] sm:min-w-[150px]", "w-auto min-w-[120px] overflow-visible sm:w-[35%] sm:min-w-[150px]",
isLastRow && "rounded-br-lg", isLastRow && "rounded-br-lg",
)} )}
> >
@@ -121,7 +121,7 @@ export default function MembersPage() {
</div> </div>
<div <div
className={twMerge( className={twMerge(
"relative", "relative z-50",
(workspace.role !== "admin" || showSkeleton) && "hidden", (workspace.role !== "admin" || showSkeleton) && "hidden",
)} )}
> >
@@ -172,10 +172,10 @@ export default function MembersPage() {
</div> </div>
<div className="mt-8 flow-root"> <div className="mt-8 flow-root">
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> <div className="-mx-4 -my-2 sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full px-4 py-2 align-middle sm:px-6 lg:px-8"> <div className="inline-block min-w-full overflow-x-auto px-4 py-2 pb-16 align-middle sm:px-6 lg:px-8">
<div className="h-full shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg"> <div className="h-full shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
<table className="min-w-full divide-y divide-light-600 dark:divide-dark-600"> <table className="min-w-full divide-y divide-light-600 overflow-visible dark:divide-dark-600">
<thead className="rounded-t-lg bg-light-300 dark:bg-dark-200"> <thead className="rounded-t-lg bg-light-300 dark:bg-dark-200">
<tr> <tr>
<th <th
@@ -192,7 +192,7 @@ export default function MembersPage() {
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-light-600 bg-light-50 dark:divide-dark-600 dark:bg-dark-100"> <tbody className="divide-y divide-light-600 overflow-visible bg-light-50 dark:divide-dark-600 dark:bg-dark-100">
{!isLoading && {!isLoading &&
data?.members.map((member, index) => ( data?.members.map((member, index) => (
<TableRow <TableRow

View File

@@ -276,21 +276,6 @@ export const boardRouter = createTRPCRouter({
await assertUserInWorkspace(ctx.db, userId, board.workspaceId); await assertUserInWorkspace(ctx.db, userId, board.workspaceId);
if (input.slug) {
const isBoardSlugAvailable = await boardRepo.isBoardSlugAvailable(
ctx.db,
input.slug,
board.workspaceId,
);
if (!isBoardSlugAvailable) {
throw new TRPCError({
message: `Board slug ${input.slug} is not available`,
code: "BAD_REQUEST",
});
}
}
const result = await boardRepo.update(ctx.db, { const result = await boardRepo.update(ctx.db, {
name: input.name, name: input.name,
slug: input.slug, slug: input.slug,
@@ -422,23 +407,11 @@ export const boardRouter = createTRPCRouter({
}), }),
) )
.query(async ({ ctx, input }) => { .query(async ({ ctx, input }) => {
const board = await boardRepo.getWorkspaceAndBoardIdByBoardPublicId(
ctx.db,
input.boardPublicId,
);
if (!board)
throw new TRPCError({
message: `Board with public ID ${input.boardPublicId} not found`,
code: "NOT_FOUND",
});
const isBoardSlugAvailable = await boardRepo.isBoardSlugAvailable( const isBoardSlugAvailable = await boardRepo.isBoardSlugAvailable(
ctx.db, ctx.db,
input.boardSlug, input.boardSlug,
board.workspaceId, input.boardPublicId,
); );
return { return {
isReserved: !isBoardSlugAvailable, isReserved: !isBoardSlugAvailable,
}; };

View File

@@ -1,4 +1,4 @@
import { and, asc, desc, eq, inArray, isNull, or } from "drizzle-orm"; import { and, asc, desc, eq, exists, inArray, isNull, or, sql } from "drizzle-orm";
import type { dbClient } from "@kan/db/client"; import type { dbClient } from "@kan/db/client";
import type { BoardVisibilityStatus } from "@kan/db/schema"; import type { BoardVisibilityStatus } from "@kan/db/schema";
@@ -481,18 +481,30 @@ export const getWorkspaceAndBoardIdByBoardPublicId = async (
export const isBoardSlugAvailable = async ( export const isBoardSlugAvailable = async (
db: dbClient, db: dbClient,
boardSlug: string, boardSlug: string,
workspaceId: number, boardPublicId: string,
) => { ) => {
const result = await db.query.boards.findFirst({ const result = await db
columns: { .select({ id: boards.id })
id: true, .from(boards)
}, .where(
where: and( and(
eq(boards.slug, boardSlug), eq(boards.publicId, boardPublicId),
eq(boards.workspaceId, workspaceId), exists(
isNull(boards.deletedAt), db
), .select({ id: boards.id })
}); .from(boards)
.where(
and(
eq(boards.slug, boardSlug),
eq(boards.workspaceId, sql`${boards.workspaceId}`), // Reference outer query's workspaceId
isNull(boards.deletedAt),
),
)
.limit(1),
),
),
)
.limit(1);
return result === undefined; return result.length === 0;
}; };