From 78b9de869fc477d20ed480dd657e0f972cf9ee95 Mon Sep 17 00:00:00 2001 From: Henry <30578846+hjball@users.noreply.github.com> Date: Mon, 2 Feb 2026 22:25:54 +0000 Subject: [PATCH] fix: prevent validation errors in workspace/card queries (#356) * fix: prevent workspace.byId validation errors when publicId is empty * fix: add keys to shortcut elements * fix: prevent card.byId validation errors when cardPublicId is empty * chore: remove invalid config option from next.config.js --- apps/web/next.config.js | 7 ----- apps/web/src/components/SideNavigation.tsx | 7 +++-- apps/web/src/providers/keyboard-shortcuts.tsx | 29 +++++++++++++++---- apps/web/src/utils/cardInvalidation.ts | 2 ++ .../views/card/components/ActivityList.tsx | 2 +- apps/web/src/views/card/index.tsx | 14 +++++---- apps/web/src/views/members/index.tsx | 10 ++++--- apps/web/src/views/public/board/CardModal.tsx | 2 +- .../views/settings/PermissionsSettings.tsx | 8 +++-- .../src/views/settings/WorkspaceSettings.tsx | 7 +++-- .../UpdateWorkspaceEmailVisibilityForm.tsx | 8 +++-- 11 files changed, 60 insertions(+), 36 deletions(-) diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 03003b73..ebdf42fe 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -53,7 +53,6 @@ const config = { { protocol: 'https', hostname: 'cdn.discordapp.com', - pathname: '/avatars/**', }, ]; @@ -95,12 +94,6 @@ const config = { swcPlugins: [["@lingui/swc-plugin", {}]], }, - api: { - bodyParser: { - sizeLimit: env("NEXT_API_BODY_SIZE_LIMIT") || '1mb', - }, - }, - async rewrites() { return [ { diff --git a/apps/web/src/components/SideNavigation.tsx b/apps/web/src/components/SideNavigation.tsx index 76a3bfe1..ce032e69 100644 --- a/apps/web/src/components/SideNavigation.tsx +++ b/apps/web/src/components/SideNavigation.tsx @@ -55,9 +55,10 @@ export default function SideNavigation({ const [isInitialised, setIsInitialised] = useState(false); const { openModal } = useModal(); - const { data: workspaceData } = api.workspace.byId.useQuery({ - workspacePublicId: workspace.publicId, - }); + const { data: workspaceData } = api.workspace.byId.useQuery( + { workspacePublicId: workspace.publicId }, + { enabled: !!workspace.publicId && workspace.publicId.length >= 12 }, + ); const subscriptions = workspaceData?.subscriptions as | Subscription[] diff --git a/apps/web/src/providers/keyboard-shortcuts.tsx b/apps/web/src/providers/keyboard-shortcuts.tsx index 089dea32..0c08a043 100644 --- a/apps/web/src/providers/keyboard-shortcuts.tsx +++ b/apps/web/src/providers/keyboard-shortcuts.tsx @@ -1,4 +1,5 @@ import type { ReactNode } from "react"; +import React from "react"; import { Dialog, DialogBackdrop, @@ -464,19 +465,37 @@ function FormattedShortcut({ shortcut }: { shortcut: KeyboardShortcut }) { ? stroke.modifiers.map(stringifyModifier) : []; - modifierStrings.forEach((mod) => { - parts.push({mod}); + modifierStrings.forEach((mod, index) => { + parts.push( + + {mod} + , + ); }); - parts.push({stroke.key.toUpperCase()}); + parts.push( + + {stroke.key.toUpperCase()} + , + ); return parts; }; if (shortcut.type === "SEQUENCE") { const parts: ReactNode[] = []; - shortcut.strokes.forEach((stroke) => { - parts.push(...formatStroke(stroke)); + shortcut.strokes.forEach((stroke, strokeIndex) => { + const strokeParts = formatStroke(stroke); + // Add stroke index to keys to ensure uniqueness across multiple strokes + const keyedParts = strokeParts.map((part, partIndex) => { + if (React.isValidElement(part)) { + return React.cloneElement(part, { + key: `stroke-${strokeIndex}-${part.key || partIndex}`, + }); + } + return part; + }); + parts.push(...keyedParts); }); return {parts}; } diff --git a/apps/web/src/utils/cardInvalidation.ts b/apps/web/src/utils/cardInvalidation.ts index ce56ffe9..0e8fc7ab 100644 --- a/apps/web/src/utils/cardInvalidation.ts +++ b/apps/web/src/utils/cardInvalidation.ts @@ -8,6 +8,8 @@ export async function invalidateCard( utils: ReturnType, cardPublicId: string, ) { + if (!cardPublicId || cardPublicId.length < 12) return; + await Promise.all([ utils.card.byId.invalidate({ cardPublicId }), utils.card.getActivities.invalidate({ cardPublicId }), diff --git a/apps/web/src/views/card/components/ActivityList.tsx b/apps/web/src/views/card/components/ActivityList.tsx index 5102a927..95fdfcaf 100644 --- a/apps/web/src/views/card/components/ActivityList.tsx +++ b/apps/web/src/views/card/components/ActivityList.tsx @@ -363,7 +363,7 @@ const ActivityList = ({ limit: ACTIVITIES_PAGE_SIZE, }, { - enabled: !!cardPublicId, + enabled: !!cardPublicId && cardPublicId.length >= 12, }, ); diff --git a/apps/web/src/views/card/index.tsx b/apps/web/src/views/card/index.tsx index 7a06e99d..3425f808 100644 --- a/apps/web/src/views/card/index.tsx +++ b/apps/web/src/views/card/index.tsx @@ -53,9 +53,10 @@ export function CardRightPanel({ isTemplate }: { isTemplate?: boolean }) { ? router.query.cardId[0] : router.query.cardId; - const { data: card } = api.card.byId.useQuery({ - cardPublicId: cardId ?? "", - }); + const { data: card } = api.card.byId.useQuery( + { cardPublicId: cardId ?? "" }, + { enabled: !!cardId && cardId.length >= 12 }, + ); const isCreator = card?.createdBy && session?.user.id === card.createdBy; const canEdit = canEditCard || isCreator; @@ -184,9 +185,10 @@ export default function CardPage({ isTemplate }: { isTemplate?: boolean }) { ? router.query.cardId[0] : router.query.cardId; - const { data: card, isLoading } = api.card.byId.useQuery({ - cardPublicId: cardId ?? "", - }); + const { data: card, isLoading } = api.card.byId.useQuery( + { cardPublicId: cardId ?? "" }, + { enabled: !!cardId && cardId.length >= 12 }, + ); const isCreator = card?.createdBy && session?.user.id === card.createdBy; const canEdit = canEditCard || isCreator; diff --git a/apps/web/src/views/members/index.tsx b/apps/web/src/views/members/index.tsx index ca91c0d4..035be336 100644 --- a/apps/web/src/views/members/index.tsx +++ b/apps/web/src/views/members/index.tsx @@ -37,7 +37,7 @@ export default function MembersPage() { const { data, isLoading } = api.workspace.byId.useQuery( { workspacePublicId: workspace.publicId }, - // { enabled: workspace?.publicId ? true : false }, + { enabled: !!workspace.publicId && workspace.publicId.length >= 12 }, ); const { data: session } = authClient.useSession(); @@ -48,9 +48,11 @@ export default function MembersPage() { const updateRoleMutation = api.member.updateRole.useMutation({ onSuccess: async () => { - await utils.workspace.byId.invalidate({ - workspacePublicId: workspace.publicId, - }); + if (workspace.publicId && workspace.publicId.length >= 12) { + await utils.workspace.byId.invalidate({ + workspacePublicId: workspace.publicId, + }); + } showPopup({ header: t`Role updated`, diff --git a/apps/web/src/views/public/board/CardModal.tsx b/apps/web/src/views/public/board/CardModal.tsx index 6e6ef963..35e65a61 100644 --- a/apps/web/src/views/public/board/CardModal.tsx +++ b/apps/web/src/views/public/board/CardModal.tsx @@ -32,7 +32,7 @@ export function CardModal({ cardPublicId: cardPublicId ?? "", }, { - enabled: isOpen && !!cardPublicId, + enabled: isOpen && !!cardPublicId && cardPublicId.length >= 12, }, ); diff --git a/apps/web/src/views/settings/PermissionsSettings.tsx b/apps/web/src/views/settings/PermissionsSettings.tsx index 10e98750..66647098 100644 --- a/apps/web/src/views/settings/PermissionsSettings.tsx +++ b/apps/web/src/views/settings/PermissionsSettings.tsx @@ -28,9 +28,11 @@ export default function PermissionsSettings() { }); // Refresh any relevant workspace data - await utils.workspace.byId.invalidate({ - workspacePublicId: workspace.publicId, - }); + if (workspace.publicId && workspace.publicId.length >= 12) { + await utils.workspace.byId.invalidate({ + workspacePublicId: workspace.publicId, + }); + } }, onError: () => { showPopup({ diff --git a/apps/web/src/views/settings/WorkspaceSettings.tsx b/apps/web/src/views/settings/WorkspaceSettings.tsx index 175eeb84..008f89d7 100644 --- a/apps/web/src/views/settings/WorkspaceSettings.tsx +++ b/apps/web/src/views/settings/WorkspaceSettings.tsx @@ -31,9 +31,10 @@ export default function WorkspaceSettings() { const { data } = api.user.getUser.useQuery(); const [hasOpenedUpgradeModal, setHasOpenedUpgradeModal] = useState(false); - const { data: workspaceData } = api.workspace.byId.useQuery({ - workspacePublicId: workspace.publicId, - }); + const { data: workspaceData } = api.workspace.byId.useQuery( + { workspacePublicId: workspace.publicId }, + { enabled: !!workspace.publicId && workspace.publicId.length >= 12 }, + ); const subscriptions = workspaceData?.subscriptions as | Subscription[] diff --git a/apps/web/src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx b/apps/web/src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx index 1766cefb..2c783f0e 100644 --- a/apps/web/src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx +++ b/apps/web/src/views/settings/components/UpdateWorkspaceEmailVisibilityForm.tsx @@ -22,9 +22,11 @@ export default function UpdateWorkspaceEmailVisibilityForm({ const updateWorkspace = api.workspace.update.useMutation({ onSuccess: () => { - void utils.workspace.byId.invalidate({ - workspacePublicId, - }); + if (workspacePublicId && workspacePublicId.length >= 12) { + void utils.workspace.byId.invalidate({ + workspacePublicId, + }); + } }, });