fix(FR-2813): render folder-create notification with VFolder node card#7260
Conversation
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 react-coverage (./react)
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Pull request overview
This PR updates the folder-create success notification to use an i18n interpolation placeholder instead of concatenating the folder name with a translated suffix, improving translation quality (word order, punctuation) across locales.
Changes:
- Updated
data.folders.FolderCreatedtranslations to include a{{name}}placeholder across multiple locale JSON files. - Updated folder creation notifications in React components to call
t('data.folders.FolderCreated', { name })instead of string concatenation. - Ensured all current call sites for
data.folders.FolderCreatedpass thenameinterpolation parameter.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| resources/i18n/zh-TW.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/zh-CN.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/vi.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/tr.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/th.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/ru.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/pt.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/pt-BR.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/pl.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/ms.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/mn.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/ko.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/ja.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/it.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/id.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/fr.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/fi.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/es.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/en.json | Add {{name}} placeholder to FolderCreated translation (wording updated). |
| resources/i18n/el.json | Add {{name}} placeholder to FolderCreated translation. |
| resources/i18n/de.json | Add {{name}} placeholder to FolderCreated translation. |
| react/src/components/ImportRepoForm.tsx | Use i18n interpolation ({ name }) for folder-create success notification. |
| react/src/components/FolderCreateModalV2.tsx | Use i18n interpolation ({ name }) for folder-create success notification. |
| react/src/components/FolderCreateModal.tsx | Use i18n interpolation ({ name }) for folder-create success notification. |
833472e to
8ea186b
Compare
b8bcd94 to
fd162d6
Compare
fd162d6 to
0b0343b
Compare
0b0343b to
6a93cd6
Compare
6a93cd6 to
f1b6d04
Compare
c26b016 to
19582de
Compare
19582de to
a886b42
Compare
nowgnuesLee
left a comment
There was a problem hiding this comment.
en: Created the folder
ko: 폴더를 생성하였습니다..
a886b42 to
7f0a251
Compare
Merge activity
|
#7260) Resolves #7245(FR-2813) ## Summary Folder-create success notifications previously rendered as `${name}: ${message}`, which users misread as if the trailing colon were part of the folder name (e.g., `AAAA: 폴더가 생성되었습니다` was read as folder `AAAA:`). Rather than papering over this with an i18n placeholder, this PR migrates the success notification to the same rich **node card** layout already used for session creation — `Folder: <name>` title where the folder name is a clickable link, and a separate `Folder created.` body. The folder-name link opens the global `FolderExplorerOpener` modal in place rather than navigating to `/data`. | Before | After | |---|---| | `AAAA: 폴더가 생성되었습니다` (single-line concatenation, ambiguous colon) | Title `폴더: AAAA` (clickable link) + body `폴더가 생성되었습니다.` | ## Changes ### Folder-create notifications now use `BAINodeNotificationItem` - `FolderCreateModalV2.tsx` — both `createVfolderV2` and `createVFolderInProject` mutation responses now spread `...BAINodeNotificationItemFragment @alias(as: "notificationFrgmt")`. `upsertNotification({ message, toText, to })` becomes `upsertNotification({ node, description })`. - `ImportRepoForm.tsx` — now uses the `createVfolderV2` mutation directly so the fragment is available on the response without a separate `vfolder_node` lookup. ### `vfolderStatus: status` alias on the V2 mutation V2 `VFolder.status: VFolderOperationStatus!` collides with V1 `VirtualFolderNode.status: String` and `ComputeSessionNode.status: String` whenever a producer selects `VFolder.status` directly while the same document spreads the polymorphic `BAINodeNotificationItemFragment`. Aliased on the V2 side as `vfolderStatus: status` — this matches the existing `VFolderNodesV2Fragment` workaround. The alias becomes unnecessary only after the legacy `VirtualFolderNode` branch and the `ComputeSessionNode.status` selections are removed (separate Strawberry-V2 migration epic). ### Folder-name link now opens the global explorer in place - `BAIVirtualFolderNodeNotificationItem.tsx` (V1) and `BAIVirtualFolderNodeNotificationItemV2.tsx` (V2) switched the title-link `onClick` from `navigate('/data?folder=<id>')` to `useFolderExplorerOpener().open(id)`. The global `FolderExplorerOpener` is mounted at the route root and listens to the `folder` URL param, so setting it without changing the path opens the modal wherever the user currently is. - This affects **all** existing folder notifications (delete / restore / delete-forever errors from `VFolderNodes.tsx` V1 and `VFolderNodesV2.tsx`), not just creation. ### File rename to V1↔V2 convention `BAIVFolderNotificationItem.tsx` → `BAIVirtualFolderNodeNotificationItemV2.tsx` (component, props interface, and Relay fragment renamed in lockstep) so the V1↔V2 pair follows the rest of the project's naming pattern (`BAIVirtualFolderNodeNotificationItem` ↔ `BAIVirtualFolderNodeNotificationItemV2`). ### Failure path now uses the same rich notification format Previously a folder-create failure surfaced through an inline `message.error()` toast, which felt inconsistent next to the rich success card. - The mutation call is wrapped in its own `try/catch` so **only creation-stage errors** land in the catch branch (form validation and the post-create session-start path each keep their own dedicated error handling). - On failure, `upsertNotification` renders the same `Folder: <name>` title (using the form-input folder name) + `Failed to create folder.` body. The resolved backend message goes into `extraDescription` so the user can expand "See detail" for the raw text. - New i18n key `data.folders.FolderCreationFailed` is added with translations for all 22 locales. ### Graceful fallback when the mutation resolves without a payload If `createVfolderV2` / `createVFolderInProject` resolves successfully but the response payload is empty (`createVfolderV2: null`), the code can no longer access the vfolder id/fragment. In that case the notification falls back to a plain `Folder: <input-name>` title + `Folder created.` body — no link, no rich card — instead of throwing on a null deref. For `ImportRepoForm` this also short-circuits before launching the import session (we don't have an id to mount). ### Cleanup - Dropped redundant `?? null` on `vfolder.notificationFrgmt` — the schema already guarantees the field is non-null when the vfolder is present (addresses reviewer feedback). - Removed dead `document.dispatchEvent('backend-ai-folder-list-changed')` and `'backend-ai-folder-created'` calls in `FolderCreateModalV2.tsx` — leftover lit-component plumbing with no remaining listeners in the React source tree. - Replaced the unused `FolderCreationResponse` interface (12 manually maintained fields, never imported by callers) with a type alias derived from the generated mutation `$data`. Callers only do truthy checks on the response, so the change is behavior-preserving. ### Reverted - The earlier `data.folders.FolderCreated` `{{name}}` placeholder change is **reverted** in all 22 locales — the folder name now lives in the title, not in the body string. - `react/src/components/FolderCreateModal.tsx` (V1, no longer imported anywhere) is reverted to the `main` state. ## Verification - Relay: PASS - Lint: PASS - Format: PASS - TypeScript: only pre-existing `main` failures (`packages/backend.ai-client/src/client.ts`, `DeleteForeverVFolderModalV2.tsx`, `VFolderDeployModal.tsx`) — none introduced by this PR. ## Test plan - [ ] Create a vfolder: confirm the success notification renders as the rich card with `폴더: <이름>` title and body `폴더가 생성되었습니다.` - [ ] Click the folder name in the success notification: the global folder explorer modal opens **in place** (no page navigation). - [ ] Trigger a folder-create failure (e.g., duplicate name, insufficient permission): confirm the failure notification renders with the rich `폴더: <이름>` title + `폴더 생성에 실패했습니다.` body, and that "See detail" expands the raw backend message. - [ ] On the V1 list (`/data` user folders, admin folders): trigger a delete / restore / delete-forever error and confirm the error card still renders with the folder name link, and clicking it opens the explorer modal in place. - [ ] On the V2 list (Project Admin Data page): same delete / restore error check. - [ ] Repo import flow (`ImportRepoForm`): create a vfolder via GitHub URL and confirm the same rich notification appears.
7f0a251 to
004104b
Compare

Resolves #7245(FR-2813)
Summary
Folder-create success notifications previously rendered as
${name}: ${message}, which users misread as if the trailing colon were part of the folder name (e.g.,AAAA: 폴더가 생성되었습니다was read as folderAAAA:).Rather than papering over this with an i18n placeholder, this PR migrates the success notification to the same rich node card layout already used for session creation —
Folder: <name>title where the folder name is a clickable link, and a separateFolder created.body. The folder-name link opens the globalFolderExplorerOpenermodal in place rather than navigating to/data.AAAA: 폴더가 생성되었습니다(single-line concatenation, ambiguous colon)폴더: AAAA(clickable link) + body폴더가 생성되었습니다.Changes
Folder-create notifications now use
BAINodeNotificationItemFolderCreateModalV2.tsx— bothcreateVfolderV2andcreateVFolderInProjectmutation responses now spread...BAINodeNotificationItemFragment @alias(as: "notificationFrgmt").upsertNotification({ message, toText, to })becomesupsertNotification({ node, description }).ImportRepoForm.tsx— now uses thecreateVfolderV2mutation directly so the fragment is available on the response without a separatevfolder_nodelookup.vfolderStatus: statusalias on the V2 mutationV2
VFolder.status: VFolderOperationStatus!collides with V1VirtualFolderNode.status: StringandComputeSessionNode.status: Stringwhenever a producer selectsVFolder.statusdirectly while the same document spreads the polymorphicBAINodeNotificationItemFragment. Aliased on the V2 side asvfolderStatus: status— this matches the existingVFolderNodesV2Fragmentworkaround. The alias becomes unnecessary only after the legacyVirtualFolderNodebranch and theComputeSessionNode.statusselections are removed (separate Strawberry-V2 migration epic).Folder-name link now opens the global explorer in place
BAIVirtualFolderNodeNotificationItem.tsx(V1) andBAIVirtualFolderNodeNotificationItemV2.tsx(V2) switched the title-linkonClickfromnavigate('/data?folder=<id>')touseFolderExplorerOpener().open(id). The globalFolderExplorerOpeneris mounted at the route root and listens to thefolderURL param, so setting it without changing the path opens the modal wherever the user currently is.VFolderNodes.tsxV1 andVFolderNodesV2.tsx), not just creation.File rename to V1↔V2 convention
BAIVFolderNotificationItem.tsx→BAIVirtualFolderNodeNotificationItemV2.tsx(component, props interface, and Relay fragment renamed in lockstep) so the V1↔V2 pair follows the rest of the project's naming pattern (BAIVirtualFolderNodeNotificationItem↔BAIVirtualFolderNodeNotificationItemV2).Failure path now uses the same rich notification format
Previously a folder-create failure surfaced through an inline
message.error()toast, which felt inconsistent next to the rich success card.try/catchso only creation-stage errors land in the catch branch (form validation and the post-create session-start path each keep their own dedicated error handling).upsertNotificationrenders the sameFolder: <name>title (using the form-input folder name) +Failed to create folder.body. The resolved backend message goes intoextraDescriptionso the user can expand "See detail" for the raw text.data.folders.FolderCreationFailedis added with translations for all 22 locales.Graceful fallback when the mutation resolves without a payload
If
createVfolderV2/createVFolderInProjectresolves successfully but the response payload is empty (createVfolderV2: null), the code can no longer access the vfolder id/fragment. In that case the notification falls back to a plainFolder: <input-name>title +Folder created.body — no link, no rich card — instead of throwing on a null deref. ForImportRepoFormthis also short-circuits before launching the import session (we don't have an id to mount).Cleanup
?? nullonvfolder.notificationFrgmt— the schema already guarantees the field is non-null when the vfolder is present (addresses reviewer feedback).document.dispatchEvent('backend-ai-folder-list-changed')and'backend-ai-folder-created'calls inFolderCreateModalV2.tsx— leftover lit-component plumbing with no remaining listeners in the React source tree.FolderCreationResponseinterface (12 manually maintained fields, never imported by callers) with a type alias derived from the generated mutation$data. Callers only do truthy checks on the response, so the change is behavior-preserving.Reverted
data.folders.FolderCreated{{name}}placeholder change is reverted in all 22 locales — the folder name now lives in the title, not in the body string.react/src/components/FolderCreateModal.tsx(V1, no longer imported anywhere) is reverted to themainstate.Verification
mainfailures (packages/backend.ai-client/src/client.ts,DeleteForeverVFolderModalV2.tsx,VFolderDeployModal.tsx) — none introduced by this PR.Test plan
폴더: <이름>title and body폴더가 생성되었습니다.폴더: <이름>title +폴더 생성에 실패했습니다.body, and that "See detail" expands the raw backend message./datauser folders, admin folders): trigger a delete / restore / delete-forever error and confirm the error card still renders with the folder name link, and clicking it opens the explorer modal in place.ImportRepoForm): create a vfolder via GitHub URL and confirm the same rich notification appears.