fix(cases): resolve descendant cases server-side to avoid HTTP 414 on deep folders#236
Merged
therealbrad merged 2 commits intomainfrom Apr 23, 2026
Conversation
…by POST - Introduced a new mock for the `useFindManyRepositoryCasesByDescendants` hook in `Cases.test.tsx` to simulate data fetching. - Updated the `Cases.tsx` component to integrate the new hook, allowing for the retrieval of cases based on descendant folder IDs. - Enhanced the repository case list query to accommodate both standard and descendant fetching modes, improving the handling of deeply nested folder structures. - Added a new entry to `.prettierignore` for local GSD planning artifacts.
Switch the by-folder-descendants endpoint from a hand-rolled project-access clause to getEnhancedDb(), so ZenStack @@Allow('read') runs per-row on the count + findMany queries. Closes the gaps where the inline clause was looser than the schema (e.g. access==NONE with stale userPermissions, GLOBAL_ROLE without a role, defaultAccessType==GLOBAL_ROLE without auth().role, etc.). The recursive CTE keeps using raw $queryRaw — it's gated by the enhanced projects.findUnique, and folder read access is derived from project read access in schema.zmodel. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
🎉 This PR is included in version 0.22.8 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes HTTP 414 "URI Too Long" errors when "Show all descendants" is toggled on for a folder with a deep / wide subtree. Previously, the client walked the folder tree, collected every descendant folder ID, and sent them to ZenStack as
{ folderId: { in: [...hundreds of ids...] } }via a GET request. Deep trees pushed the serialized query string past the server's URI length limit.The fix keeps descendant resolution server-side via a POST endpoint backed by a recursive CTE, so the wire payload is bounded to a single
folderIdregardless of tree depth.Server
POST /api/projects/[projectId]/cases/by-folder-descendantsRepositoryFoldersprojectId+folderId: { in: [descendants] }server-side so the client can't use it to query outside the authorized subtree{ cases, totalCount }in one round-tripgetEnhancedDb(session)— ZenStack's@@allow('read')onRepositoryCasesis enforced per-row, which is stricter than the hand-rolled project-access clause used byfetch-many/bulk-edit. Closes gaps aroundaccess == 'NONE'users with staleuserPermissions,GLOBAL_ROLEgrants without a role, etc.$queryRaw(SQL is opaque to policies), but it's gated by the enhancedprojects.findUniquefirst and folder read access is schema-derived from project read access, so it's safe.Client
useFindManyRepositoryCasesByDescendants— thinuseQuerywrapper that returns the same{ data, isLoading, totalCount, refetch }shape as the ZenStack wrapper, including post-fetch text/link/steps filters and client-side paginationCases.tsx:selectinto a module-scopeREPOSITORY_CASE_LIST_SELECT(single source for both hooks)isDescendantsModeflag andrepositoryCaseWhereClauseWithoutFolderFilterisDescendantsModeis active; the parallel descendants-POST counterparts take overdata / isLoading / filteredTotalCount / refetchDataandtotalRepositoryCasesthrough whichever hook is activeRelated Issue
Closes #(issue number)
Type of Change
How Has This Been Tested?
Cases.test.tsxtests pass (the existingshowDescendantstest now exercises the POST-mode path via a mocked descendants hook)useRepositoryCasesWithFilteredFields.integration.test.tsxpasses (15/15)Test Configuration:
.nvmrcChecklist
select-sharing)Cases.test.tsxmock so the existingshowDescendantstest now covers the POST-mode path)Screenshots (if applicable)
Additional Notes
POSTendpoint accepts the client'swhere,orderBy, andselectas pass-through JSON.projectIdandfolderIdare force-overridden server-side after the client'swhereis spread, soOR/ANDtricks can't escape the subtree or cross projects.descendantFolderIds(computed inProjectRepository) is still produced client-side: it's used as a signal that descendants mode is active, as input tofolderPathMapfor displaying relative paths, and by the export server action (which already POSTs, so URL length isn't an issue there).useFindManyTestRunCases,useCountTestRunCases) are untouched — "Show all descendants" is a repository-view-only toggle, so run mode never sees a hugefolderIdarray. If run mode ever gains the toggle, the same pattern can be extended.fetch-manyandbulk-editstill use the looser inline pattern; migrating them is a separate concern.