Skip to content

fix(FR-2813): render folder-create notification with VFolder node card#7260

Merged
graphite-app[bot] merged 1 commit into
mainfrom
05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder
May 13, 2026
Merged

fix(FR-2813): render folder-create notification with VFolder node card#7260
graphite-app[bot] merged 1 commit into
mainfrom
05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder

Conversation

@ironAiken2
Copy link
Copy Markdown
Contributor

@ironAiken2 ironAiken2 commented May 6, 2026

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.tsxBAIVirtualFolderNodeNotificationItemV2.tsx (component, props interface, and Relay fragment renamed in lockstep) so the V1↔V2 pair follows the rest of the project's naming pattern (BAIVirtualFolderNodeNotificationItemBAIVirtualFolderNodeNotificationItemV2).

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.

Copilot AI review requested due to automatic review settings May 6, 2026 07:01
@github-actions github-actions Bot added area:ux UI / UX issue. area:i18n Localization labels May 6, 2026
Copy link
Copy Markdown
Contributor Author

ironAiken2 commented May 6, 2026


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 May 6, 2026

Coverage Report for react-coverage (./react)

Status Category Percentage Covered / Total
🔵 Lines 6.45% 1783 / 27631
🔵 Statements 5.3% 1978 / 37267
🔵 Functions 5.18% 296 / 5713
🔵 Branches 3.71% 1293 / 34789
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
react/src/components/BAINodeNotificationItem.tsx 0% 0% 0% 0% 18-80
react/src/components/BAIVirtualFolderNodeNotificationItem.tsx 0% 0% 0% 0% 34-57
react/src/components/FolderCreateModalV2.tsx 0% 0% 0% 0% 50-729
react/src/components/ImportRepoForm.tsx 0% 0% 0% 0% 38-419
Generated in workflow #638 for commit 004104b by the Vitest Coverage Report Action

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

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.FolderCreated translations 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.FolderCreated pass the name interpolation 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.

Comment thread resources/i18n/en.json Outdated
Comment thread resources/i18n/zh-TW.json Outdated
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch from 833472e to 8ea186b Compare May 7, 2026 01:45
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch 2 times, most recently from b8bcd94 to fd162d6 Compare May 7, 2026 03:25
@github-actions github-actions Bot added size:L 100~500 LoC and removed size:M 30~100 LoC labels May 7, 2026
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch from fd162d6 to 0b0343b Compare May 7, 2026 03:29
@github-actions github-actions Bot added size:M 30~100 LoC and removed size:L 100~500 LoC labels May 7, 2026
@ironAiken2 ironAiken2 changed the title fix(FR-2813): replace folder-create notification concatenation with i18n placeholder fix(FR-2813): render folder-create notification with VFolder node card May 7, 2026
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch from 0b0343b to 6a93cd6 Compare May 8, 2026 06:42
Comment thread react/src/components/ImportRepoForm.tsx Outdated
Comment thread react/src/components/FolderCreateModalV2.tsx
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch from 6a93cd6 to f1b6d04 Compare May 11, 2026 10:16
@github-actions github-actions Bot added size:L 100~500 LoC and removed size:M 30~100 LoC labels May 11, 2026
@ironAiken2 ironAiken2 requested a review from nowgnuesLee May 11, 2026 10:16
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch 2 times, most recently from c26b016 to 19582de Compare May 12, 2026 01:57
Comment thread react/src/components/ImportRepoForm.tsx Outdated
Comment thread react/src/components/FolderCreateModalV2.tsx Outdated
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch from 19582de to a886b42 Compare May 12, 2026 04:12
@ironAiken2 ironAiken2 requested a review from nowgnuesLee May 12, 2026 04:14
Copy link
Copy Markdown
Contributor

@nowgnuesLee nowgnuesLee left a comment

Choose a reason for hiding this comment

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

en: Created the folder
ko: 폴더를 생성하였습니다..

@ironAiken2 ironAiken2 requested a review from nowgnuesLee May 12, 2026 09:40
@ironAiken2 ironAiken2 force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch from a886b42 to 7f0a251 Compare May 12, 2026 09:40
Copy link
Copy Markdown
Contributor

@agatha197 agatha197 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Copy Markdown
Contributor

@nowgnuesLee nowgnuesLee left a comment

Choose a reason for hiding this comment

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

LGTM

@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented May 13, 2026

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.
@graphite-app graphite-app Bot force-pushed the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch from 7f0a251 to 004104b Compare May 13, 2026 08:04
@graphite-app graphite-app Bot merged commit 004104b into main May 13, 2026
12 checks passed
@graphite-app graphite-app Bot deleted the 05-06-fix_fr-2813_replace_folder-create_notification_concatenation_with_i18n_placeholder branch May 13, 2026 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Folder creation notification reads "{name}: 폴더가 만들어졌습니다" — colon prefix is mistaken for part of the folder name

4 participants