feat(FR-2573): migrate VFolder list queries to Strawberry V2 GraphQL API#6827
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has required the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Coverage report for
|
St.❔ |
Category | Percentage | Covered / Total |
|---|---|---|---|
| 🟢 | Statements | 81.87% | 429/524 |
| 🟡 | Branches | 70.43% | 362/514 |
| 🟡 | Functions | 76.86% | 93/121 |
| 🟢 | Lines | 83.19% | 391/470 |
Test suite run success
319 tests passing in 13 suites.
Report generated by 🧪jest coverage report action from 0545687
Coverage report for
|
St.❔ |
Category | Percentage | Covered / Total |
|---|---|---|---|
| 🔴 | Statements | 8.66% (-0.11% 🔻) |
1857/21451 |
| 🔴 | Branches | 7.85% (-0.13% 🔻) |
1187/15112 |
| 🔴 | Functions | 5.09% (-0.05% 🔻) |
295/5792 |
| 🔴 | Lines | 8.4% (-0.11% 🔻) |
1749/20822 |
Show new covered files 🐣
St.❔ |
File | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
| 🔴 | ... / useVirtualFolderNodePathV2.ts |
0% | 0% | 0% | 0% |
| 🔴 | ... / EditableVFolderNameV2.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / FileBrowserButtonV2.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / FolderExplorerHeaderV2.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / FolderExplorerModalV2.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / SFTPServerButtonV2.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / VFolderLazyViewV2.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / VFolderNodeDescriptionV2.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / VirtualFolderPathV2.tsx |
0% | 100% | 0% | 0% |
Test suite run success
865 tests passing in 40 suites.
Report generated by 🧪jest coverage report action from 46c7c65
74ea66e to
d38e445
Compare
13f02e5 to
84334e5
Compare
84334e5 to
8390190
Compare
d38e445 to
1868540
Compare
8390190 to
a861afe
Compare
1868540 to
d2c94ad
Compare
a861afe to
4f71e33
Compare
d2c94ad to
a6e4a32
Compare
ea5c773 to
0886aed
Compare
a6e4a32 to
4423f2b
Compare
0886aed to
7d7a301
Compare
4423f2b to
16140ba
Compare
There was a problem hiding this comment.
Pull request overview
Migrates vfolder list pages and related table/modals from the legacy VirtualFolderNode GraphQL surface to the Strawberry V2 VFolder surface, including updated filtering/sorting and URL state handling.
Changes:
- Update user/admin vfolder list pages to V2 query shapes, structured
VFolderFilter, V2orderBy, andnuqsURL state. - Introduce V2-specific table cell/modal components and migrate shared modals/fragments to V2
VFolderfragments. - Add a new
BAIVFolderDeleteButtonV2fragment/component export inbackend.ai-ui.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| react/src/routes.tsx | Simplifies route component reference for the vfolder list page. |
| react/src/pages/VFolderNodeListPage.tsx | Migrates the user-facing list query/filter/sort state handling toward V2. |
| react/src/pages/AdminVFolderNodeListPage.tsx | Migrates the admin list query/filter/sort state handling toward V2. |
| react/src/components/VFolderNodesV2.tsx | Switches the shared table fragment and rendering from legacy node fields to V2 VFolder fields. |
| react/src/components/VFolderPermissionCellV2.tsx | New V2 mount-permission cell based on accessControl.permission. |
| react/src/components/VFolderNodeIdenticonV2.tsx | New V2 identicon cell fragment keyed off VFolder.id. |
| react/src/components/SharedFolderPermissionInfoModalV2.tsx | New V2 shared-folder permission info modal wired to V2 fields/IDs. |
| react/src/components/RestoreVFolderModalV2.tsx | Updates restore modal fragment to read V2 metadata.name. |
| react/src/components/DeleteVFolderModalV2.tsx | Updates bulk delete modal fragment to V2 and adjusts permission assumptions. |
| react/src/components/DeleteForeverVFolderModalV2.tsx | Updates purge modal fragment to V2 metadata.name. |
| packages/backend.ai-ui/src/components/fragments/index.ts | Exports the new BAIVFolderDeleteButtonV2. |
| packages/backend.ai-ui/src/components/fragments/BAIVFolderDeleteButtonV2.tsx | Adds a V2 delete button fragment/component compatible with VFolder. |
7d7a301 to
674a935
Compare
9379d35 to
305214f
Compare
84a12e2 to
0c2b58e
Compare
0c2b58e to
b7d1711
Compare
305214f to
ebed9ab
Compare
b7d1711 to
a0d3a93
Compare
9ba4c1c to
e4eb5ac
Compare
a0d3a93 to
87a3ba7
Compare
e4eb5ac to
15c48c8
Compare
87a3ba7 to
19f1bad
Compare
15c48c8 to
fe5d35a
Compare
19f1bad to
b9895f4
Compare
fe5d35a to
b4b1180
Compare
b9895f4 to
c06993e
Compare
b4b1180 to
b54fea7
Compare
c06993e to
0162303
Compare
0162303 to
f6d48a0
Compare
b54fea7 to
f68a0b2
Compare
f68a0b2 to
707aba2
Compare
f6d48a0 to
35d9e6c
Compare
707aba2 to
bdae917
Compare
35d9e6c to
7a7c311
Compare
Switch AdminVFolderNodeListPage and VFolderNodeListPage to the V2 list queries: `adminVfoldersV2` for the admin list and `myVfolders` for the user-facing list. Component-level V2 migration (VFolderNodesV2 and its inner fragments/components) lands in FR-2696 below; this PR only changes the page query path and URL state handling. URL state now uses nuqs with structured VFolderFilter / VFolderOrderBy inputs composed under a top-level AND, and `convertToOrderBy` for sort. `isDeletedCategory` accepts both V2 UPPERCASE and legacy kebab-case statuses so the remaining V1 call sites (e.g. the editable vfolder name cell) keep working.
bdae917 to
46c7c65
Compare

Resolves #6689 (FR-2573)
Summary
Migrates the virtual folder list pages —
AdminVFolderNodeListPage(super/admin/project admin) andVFolderNodeListPage(user-facing) — and the sharedVFolderNodesV2table component (with its child cells) from the legacyVirtualFolderNodeGraphQL type to the Strawberry V2VFoldertype (adminVfoldersV2/projectVfolders). Shared modals and buttons consumed by both pages are switched over in the same change to keep fragment types consistent.What changed
Pages (V2 queries)
react/src/pages/AdminVFolderNodeListPage.tsx— now queriesadminVfoldersV2.react/src/pages/VFolderNodeListPage.tsx— now queriesprojectVfolders(projectId: UUID!).Both pages now:
nuqs(useQueryStates/parseAsStringLiteral/parseAsJson<GraphQLFilter>) for URL state instead ofuse-query-params.VFolderFilterstructurally under a top-levelAND:status: { notIn: [...] }/{ in: [...] })usageMode: { equals: 'GENERAL' | 'DATA' | 'MODEL' },name: { iStartsWith/iNotStartsWith: '.' }for automount)BAIGraphQLPropertyFiltervalueconvertToOrderBy<VFolderOrderBy>to translate the-created_at/namesort DSL into{ field: VFolderOrderField, direction: OrderDirection }.useFetchKey/INITIAL_FETCH_KEYfrombackend.ai-uiin place of the legacyuseUpdatableState('initial-fetch')pattern.useBAIPaginationOptionStateOnSearchParam.V2 child components
New V2 counterparts for cells that were tightly coupled to the legacy type (version branching per request):
react/src/components/VFolderNodeIdenticonV2.tsxreact/src/components/VFolderPermissionCellV2.tsxreact/src/components/SharedFolderPermissionInfoModalV2.tsxShared fragments migrated in place
These modals/buttons are consumed only by the list pages, and their names already carry a
V2suffix or their API surface did not change, so they are migrated in place:react/src/components/DeleteVFolderModalV2.tsxreact/src/components/DeleteForeverVFolderModalV2.tsxreact/src/components/RestoreVFolderModal.tsxpackages/backend.ai-ui/src/components/fragments/BAIVFolderDeleteButton.tsx(+ stories)Fragment fields were remapped to V2 groups:
metadata { name },accessControl { permission },ownership { ... }.Delete gating: the legacy
VirtualFolderNode.permissionsarray exposed adelete_vfolderaction permission that was used to disable the delete button per user. V2VFolderdoes not yet expose an equivalent action-level permission —accessControl.permissionis aVFolderMountPermissionenum (READ_ONLY/READ_WRITE/RW_DELETE) describing the mount level, not a user's entity-level action right. Using it as a delete gate would incorrectly deny deletion for folders mounted read-only/read-write even when the user has entity-level permission. Until a proper action-permission field is exposed (tracked asTODO(needs-backend)inBAIVFolderDeleteButtonV2), the button is always enabled unless the parent explicitly disables it, and the backend rejects unauthorized requests.isDeletedCategoryhelperisDeletedCategorynow accepts both V2 UPPERCASE statuses (DELETE_PENDING, ...) and legacy kebab-case statuses (delete-pending, ...) so the remaining legacy call sites (VFolderNodes.tsx,EditableVFolderName.tsx) keep working unchanged until they are migrated.Regressions documented as TODO(needs-backend)
The current V2
VFolderFilterinput does not yet expose every property supported by the legacy filter DSL. These filters are commented out withTODO(needs-backend)markers in both list pages and should be restored once the backend extendsVFolderFilter:ownership_type(user / project)permission(ro / rw mount permission)quota_scope_idcloneablestatusis intentionally omitted from the property filter because the active/deleted tab already drives it.Also, in
VFolderNodesV2.tsxa few columns remain asTODO(needs-backend)because the V2 type does not expose them yet (num_files,cur_size,max_files,max_size).Implementation notes
VFolderOrderBy.fieldis emitted as optional in the Relay-generated types because the schema declaresfield: VFolderOrderField! = CREATED_AT(non-null with a default).convertToOrderBy<T extends { field: string; ... }>expectsfieldto be required, so the helper is invoked with a widened type and cast back toReadonlyArray<VFolderOrderBy>. This is the same trade-off as in other V2 list pages.projectVfoldersrequires a non-nullUUID!.currentProject.idis typedstring | undefined | null; the query usescurrentProject.id ?? ''to keep it non-null at the type level — Suspense/Relay behavior on the empty-string case is unchanged from the legacy page (which passedproject:${currentProject.id}).Verification
Ran
bash scripts/verify.sh— Relay / Lint / Format / TypeScript all PASS (=== ALL PASS ===).Scope boundary
Only the two list pages,
VFolderNodesV2, its three V2 child cells, and the shared modals/button fragments consumed by those pages are touched.VFolderNodes.tsx(legacy) andEditableVFolderName.tsxstill consume the legacyVirtualFolderNodetype and are intentionally left untouched.Checklist: (if applicable)
adminVfoldersV2,projectVfolders,VFolderFilter,VFolderOrderBy— added in manager 26.4.2)