Skip to content

feat(FR-2573): migrate VFolder list queries to Strawberry V2 GraphQL API#6827

Draft
ironAiken2 wants to merge 1 commit into04-21-feat_fr-2619_migrate_single_folder_detail_reads_to_strawberry_v2_vfolderv2_queryfrom
04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api
Draft

feat(FR-2573): migrate VFolder list queries to Strawberry V2 GraphQL API#6827
ironAiken2 wants to merge 1 commit into04-21-feat_fr-2619_migrate_single_folder_detail_reads_to_strawberry_v2_vfolderv2_queryfrom
04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api

Conversation

@ironAiken2
Copy link
Copy Markdown
Contributor

@ironAiken2 ironAiken2 commented Apr 21, 2026

Resolves #6689 (FR-2573)

Summary

Migrates the virtual folder list pages — AdminVFolderNodeListPage (super/admin/project admin) and VFolderNodeListPage (user-facing) — and the shared VFolderNodesV2 table component (with its child cells) from the legacy VirtualFolderNode GraphQL type to the Strawberry V2 VFolder type (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 queries adminVfoldersV2.
  • react/src/pages/VFolderNodeListPage.tsx — now queries projectVfolders(projectId: UUID!).

Both pages now:

  • Use nuqs (useQueryStates / parseAsStringLiteral / parseAsJson<GraphQLFilter>) for URL state instead of use-query-params.
  • Compose VFolderFilter structurally under a top-level AND:
    • tab-derived status filter (status: { notIn: [...] } / { in: [...] })
    • radio-derived usage-mode filter (usageMode: { equals: 'GENERAL' | 'DATA' | 'MODEL' }, name: { iStartsWith/iNotStartsWith: '.' } for automount)
    • user-supplied BAIGraphQLPropertyFilter value
  • Use convertToOrderBy<VFolderOrderBy> to translate the -created_at / name sort DSL into { field: VFolderOrderField, direction: OrderDirection }.
  • Use useFetchKey / INITIAL_FETCH_KEY from backend.ai-ui in place of the legacy useUpdatableState('initial-fetch') pattern.
  • Use the non-legacy 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.tsx
  • react/src/components/VFolderPermissionCellV2.tsx
  • react/src/components/SharedFolderPermissionInfoModalV2.tsx

Shared fragments migrated in place

These modals/buttons are consumed only by the list pages, and their names already carry a V2 suffix or their API surface did not change, so they are migrated in place:

  • react/src/components/DeleteVFolderModalV2.tsx
  • react/src/components/DeleteForeverVFolderModalV2.tsx
  • react/src/components/RestoreVFolderModal.tsx
  • packages/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.permissions array exposed a delete_vfolder action permission that was used to disable the delete button per user. V2 VFolder does not yet expose an equivalent action-level permission — accessControl.permission is a VFolderMountPermission enum (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 as TODO(needs-backend) in BAIVFolderDeleteButtonV2), the button is always enabled unless the parent explicitly disables it, and the backend rejects unauthorized requests.

isDeletedCategory helper

isDeletedCategory now 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 VFolderFilter input does not yet expose every property supported by the legacy filter DSL. These filters are commented out with TODO(needs-backend) markers in both list pages and should be restored once the backend extends VFolderFilter:

  • ownership_type (user / project)
  • permission (ro / rw mount permission)
  • quota_scope_id
  • cloneable

status is intentionally omitted from the property filter because the active/deleted tab already drives it.

Also, in VFolderNodesV2.tsx a few columns remain as TODO(needs-backend) because the V2 type does not expose them yet (num_files, cur_size, max_files, max_size).

Implementation notes

  • VFolderOrderBy.field is emitted as optional in the Relay-generated types because the schema declares field: VFolderOrderField! = CREATED_AT (non-null with a default). convertToOrderBy<T extends { field: string; ... }> expects field to be required, so the helper is invoked with a widened type and cast back to ReadonlyArray<VFolderOrderBy>. This is the same trade-off as in other V2 list pages.
  • projectVfolders requires a non-null UUID!. currentProject.id is typed string | undefined | null; the query uses currentProject.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 passed project:${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) and EditableVFolderName.tsx still consume the legacy VirtualFolderNode type and are intentionally left untouched.

Checklist: (if applicable)

  • Documentation
  • Minimum required manager version (V2 adminVfoldersV2, projectVfolders, VFolderFilter, VFolderOrderBy — added in manager 26.4.2)
  • Specific setting for review
  • Minimum requirements to check during review
  • Test case(s) to demonstrate the difference of before/after

Copy link
Copy Markdown
Contributor Author

ironAiken2 commented Apr 21, 2026

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.
Learn more


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • flow:merge-queue - adds this PR to the back of the merge queue
  • flow:hotfix - for urgent changes, fast-track this PR to the front of 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

Coverage report for ./packages/backend.ai-ui

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

Coverage report for ./react

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

@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 74ea66e to d38e445 Compare April 21, 2026 07:56
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch 2 times, most recently from 13f02e5 to 84334e5 Compare April 21, 2026 09:20
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 84334e5 to 8390190 Compare April 22, 2026 04:25
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from d38e445 to 1868540 Compare April 22, 2026 04:25
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 8390190 to a861afe Compare April 22, 2026 04:47
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 1868540 to d2c94ad Compare April 22, 2026 06:40
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from a861afe to 4f71e33 Compare April 22, 2026 06:40
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from d2c94ad to a6e4a32 Compare April 22, 2026 06:55
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch 2 times, most recently from ea5c773 to 0886aed Compare April 22, 2026 07:00
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from a6e4a32 to 4423f2b Compare April 22, 2026 07:00
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 0886aed to 7d7a301 Compare April 23, 2026 02:23
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 4423f2b to 16140ba Compare April 23, 2026 02:23
@ironAiken2 ironAiken2 marked this pull request as ready for review April 23, 2026 02:55
Copilot AI review requested due to automatic review settings April 23, 2026 02:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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, V2 orderBy, and nuqs URL state.
  • Introduce V2-specific table cell/modal components and migrate shared modals/fragments to V2 VFolder fragments.
  • Add a new BAIVFolderDeleteButtonV2 fragment/component export in backend.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.

Comment thread react/src/components/VFolderNodesV2.tsx Outdated
Comment thread react/src/pages/VFolderNodeListPage.tsx Outdated
Comment thread react/src/components/VFolderNodesV2.tsx
@ironAiken2 ironAiken2 marked this pull request as draft April 23, 2026 04:14
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 7d7a301 to 674a935 Compare April 23, 2026 04:35
@ironAiken2 ironAiken2 changed the base branch from 04-24-feat_fr-2696_create_project_admin_data_page to graphite-base/6827 April 24, 2026 06:02
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 9379d35 to 305214f Compare April 24, 2026 06:03
@ironAiken2 ironAiken2 changed the base branch from graphite-base/6827 to 04-24-feat_fr-2696_create_project_admin_data_page April 24, 2026 06:03
@ironAiken2 ironAiken2 force-pushed the 04-24-feat_fr-2696_create_project_admin_data_page branch from 0c2b58e to b7d1711 Compare April 24, 2026 06:29
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 305214f to ebed9ab Compare April 24, 2026 06:29
@ironAiken2 ironAiken2 force-pushed the 04-24-feat_fr-2696_create_project_admin_data_page branch from b7d1711 to a0d3a93 Compare April 24, 2026 06:36
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch 2 times, most recently from 9ba4c1c to e4eb5ac Compare April 27, 2026 02:42
@ironAiken2 ironAiken2 force-pushed the 04-24-feat_fr-2696_create_project_admin_data_page branch from a0d3a93 to 87a3ba7 Compare April 27, 2026 02:43
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from e4eb5ac to 15c48c8 Compare April 27, 2026 04:19
@ironAiken2 ironAiken2 force-pushed the 04-24-feat_fr-2696_create_project_admin_data_page branch from 87a3ba7 to 19f1bad Compare April 27, 2026 04:19
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 15c48c8 to fe5d35a Compare April 27, 2026 05:43
@ironAiken2 ironAiken2 force-pushed the 04-24-feat_fr-2696_create_project_admin_data_page branch from 19f1bad to b9895f4 Compare April 27, 2026 05:43
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from fe5d35a to b4b1180 Compare April 27, 2026 06:57
@ironAiken2 ironAiken2 force-pushed the 04-24-feat_fr-2696_create_project_admin_data_page branch from b9895f4 to c06993e Compare April 27, 2026 06:57
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from b4b1180 to b54fea7 Compare April 27, 2026 08:55
@ironAiken2 ironAiken2 force-pushed the 04-24-feat_fr-2696_create_project_admin_data_page branch from c06993e to 0162303 Compare April 27, 2026 08:55
@ironAiken2 ironAiken2 changed the base branch from 04-24-feat_fr-2696_create_project_admin_data_page to graphite-base/6827 April 27, 2026 10:00
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from b54fea7 to f68a0b2 Compare April 27, 2026 10:00
@ironAiken2 ironAiken2 changed the base branch from graphite-base/6827 to 04-23-feat_fr-2688_migrate_notification_item_virtualfoldernode_branch_to_strawberry_v2 April 27, 2026 10:01
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from f68a0b2 to 707aba2 Compare April 28, 2026 02:03
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2688_migrate_notification_item_virtualfoldernode_branch_to_strawberry_v2 branch from f6d48a0 to 35d9e6c Compare April 28, 2026 02:03
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from 707aba2 to bdae917 Compare April 28, 2026 03:21
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2688_migrate_notification_item_virtualfoldernode_branch_to_strawberry_v2 branch from 35d9e6c to 7a7c311 Compare April 28, 2026 03:21
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.
@ironAiken2 ironAiken2 changed the base branch from 04-23-feat_fr-2688_migrate_notification_item_virtualfoldernode_branch_to_strawberry_v2 to graphite-base/6827 April 28, 2026 06:19
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2573_migrate_vfolder_list_queries_to_strawberry_v2_graphql_api branch from bdae917 to 46c7c65 Compare April 28, 2026 06:20
@ironAiken2 ironAiken2 changed the base branch from graphite-base/6827 to 04-21-feat_fr-2619_migrate_single_folder_detail_reads_to_strawberry_v2_vfolderv2_query April 28, 2026 06:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500~ LoC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants