feat(FR-2691): relocate /data header panels — Dashboard + host-capacity cell#6941
Conversation
Coverage report for
|
St.❔ |
Category | Percentage | Covered / Total |
|---|---|---|---|
| 🔴 | Statements | 8.87% (-0.02% 🔻) |
1859/20957 |
| 🔴 | Branches | 8.05% (-0.01% 🔻) |
1187/14750 |
| 🔴 | Functions | 5.22% (+0% 🔼) |
297/5686 |
| 🔴 | Lines | 8.61% (-0.02% 🔻) |
1750/20332 |
Show new covered files 🐣
St.❔ |
File | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
| 🔴 | ... / QuotaPerStorageVolumeDashboardItem.tsx |
0% | 0% | 0% | 0% |
Test suite run success
865 tests passing in 40 suites.
Report generated by 🧪jest coverage report action from 687147d
b068ff5 to
fbabca7
Compare
2a1e7e6 to
8d4bf6b
Compare
fbabca7 to
aa129c7
Compare
8d4bf6b to
b3429c8
Compare
aa129c7 to
5ac60d3
Compare
There was a problem hiding this comment.
Pull request overview
Relocates the /data page header panels by moving folder-status information to the Dashboard, and enhances the vfolder list by surfacing per-host capacity/usage context directly in the “Host” column (with a modal entry point for per-volume quota details).
Changes:
- Removed the
/datapage’s top header panel row and promoted the folder table card to the top. - Added a new Dashboard board item rendering
StorageStatusPanelCard, including navigation to/data?invitation=true. - Reworked the vfolder table “Host” column to show a per-host usage badge and added a header tooltip icon that opens
QuotaPerStorageVolumePanelCardin a modal (plus i18n keydata.usage.Unknownacross locales).
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| react/src/pages/VFolderNodeListPage.tsx | Removes the /data header panels row and cleans up related imports/usage. |
| react/src/pages/DashboardPage.tsx | Adds the folder-status board item and wires invitation navigation to /data. |
| react/src/components/VFolderNodesV2.tsx | Replaces “Location” with “Host” column, adds host usage badge cell + quota modal trigger. |
| react/src/components/QuotaPerStorageVolumePanelCard.tsx | Refactors quota panel to be modal-body-friendly; adds defaultVolumeInfo for preselection. |
| react/src/components/StorageStatusPanelCard.tsx | Refactors layout to a Dashboard board-item body using BAIFlex + BAIBoardItemTitle. |
| resources/i18n/en.json | Adds data.usage.Unknown translation key. |
| resources/i18n/de.json | Adds data.usage.Unknown translation key. |
| resources/i18n/el.json | Adds data.usage.Unknown translation key. |
| resources/i18n/es.json | Adds data.usage.Unknown translation key. |
| resources/i18n/fi.json | Adds data.usage.Unknown translation key. |
| resources/i18n/fr.json | Adds data.usage.Unknown translation key. |
| resources/i18n/id.json | Adds data.usage.Unknown translation key. |
| resources/i18n/it.json | Adds data.usage.Unknown translation key. |
| resources/i18n/ja.json | Adds data.usage.Unknown translation key. |
| resources/i18n/ko.json | Adds data.usage.Unknown translation key. |
| resources/i18n/mn.json | Adds data.usage.Unknown translation key. |
| resources/i18n/ms.json | Adds data.usage.Unknown translation key. |
| resources/i18n/pl.json | Adds data.usage.Unknown translation key. |
| resources/i18n/pt-BR.json | Adds data.usage.Unknown translation key. |
| resources/i18n/pt.json | Adds data.usage.Unknown translation key. |
| resources/i18n/ru.json | Adds data.usage.Unknown translation key. |
| resources/i18n/th.json | Adds data.usage.Unknown translation key. |
| resources/i18n/tr.json | Adds data.usage.Unknown translation key. |
| resources/i18n/vi.json | Adds data.usage.Unknown translation key. |
| resources/i18n/zh-CN.json | Adds data.usage.Unknown translation key. |
| resources/i18n/zh-TW.json | Adds data.usage.Unknown translation key. |
824d4b3 to
058f802
Compare
|
@agatha197 Thanks for testing! Previously the host-capacity badge was only rendered when |
058f802 to
9c45759
Compare
42e2427 to
2ab0d52
Compare
c84cd7c to
91a0feb
Compare
6f4f7f0 to
1d95414
Compare
025ecbb to
dabf732
Compare
ac4de81 to
7db3eb6
Compare
dabf732 to
7a91a43
Compare
7db3eb6 to
03cf13c
Compare
2af4049 to
f1aff6a
Compare
03cf13c to
99b663c
Compare
Merge activity
|
…ty cell (#6941) resolves #6937 (FR-2691) ## Summary Clears the three header panels that used to sit above the folder table on `/data`, redistributes their responsibilities, and reshapes the "Location" column into a "Host" column that surfaces per-volume capacity info without requiring an extra click on every row. ## Changes on `/data` (`VFolderNodeListPage.tsx`) - Removed the top `Row` that rendered the Create Folder action card, `StorageStatusPanelCard`, and `QuotaPerStorageVolumePanelCard`. The Create Folder affordance is already present as the primary button inside the folder table card header, so no replacement action card is needed. - Promoted the folder table card to the top of the page. - Cleaned up now-unused imports / variables (`ActionItemContent`, `BAINewFolderIcon`, `BAIAlertIconWithTooltip`, `Grid.useBreakpoint`, `useWebUINavigate`, `ErrorBoundary`, per-row `Suspense`, `CARD_MIN_HEIGHT`). ## Changes in the folder table (`VFolderNodesV2.tsx`) - Column `title`: `data.folders.Location` (위치) → `data.Host` (호스트). - Column header affordance: a `BAIAlertIconWithTooltip` sits next to the "Host" label. Clicking it opens the `QuotaPerStorageVolumePanelCard` in a Modal, pre-selected on a quota-supporting host. The icon is hidden entirely when no volume reports `"quota"` in `capabilities`, so the modal entry point disappears when the feature is unusable — we don't open a dialog with no useful content. - Column cells: new `VFolderHostCell` renders a `StorageUsageBadge` (sourced from `vfolder.list_hosts()`, cached under the shared `['vhostInfo']` tan-query key that `StorageSelect` already uses) plus the host name. **No** per-cell click behavior — the modal is only reachable via the column-header affordance. - Badge gating matches `StorageSelect`'s own precedent: the badge renders whenever the backend attaches a `usage` object (even `{}`). `StorageUsageBadge` resolves a `percentage`-less `usage` to a neutral (uncolored) marker. The accompanying tooltip reads `Host Status: <Adequate | Caution | Insufficient | Unknown>`; the `Unknown` label is a newly added key that covers the "backend reports no percentage" case. - Switched the cell from `useSuspenseTanQuery` to `useTanQuery`. A per-cell Suspense boundary whose fallback rendered the bare host text (visually indistinguishable from the "loaded but no usage data" branch) caused rows to stick in the fallback even after `vhostInfo` resolved. ## Changes to `QuotaPerStorageVolumePanelCard.tsx` - Dropped the outer `BAICard` wrapper and the internal title. The consumer is now a `Modal` that supplies its own title and chrome, and a nested card here produced a duplicated header on top of the modal frame. - Moved the `?` tooltip icon (`QuestionCircleOutlined` with `data.HostDetails`) into the Modal title so all header affordances live in one place. - `StorageSelect` moved out of the former card's `extra` slot (right-aligned, borderless) and into the modal body as the first element, left-aligned with a sensible `minWidth`. - Added `defaultVolumeInfo?: VolumeInfo` prop. When set, the card seeds `selectedVolumeInfo` with that value and disables the built-in `autoSelectType="usage"` fallback; users can still switch volumes through the inline `StorageSelect`. This is how the header icon pre-selects a quota-supporting host. - Props type simplified: `BAICardProps` → a dedicated local interface (card-specific passthrough props no longer make sense). ## Changes on the Dashboard (`DashboardPage.tsx`, `StorageStatusPanelCard.tsx`) - Added a new `folderStatus` board item between `myResourceWithinResourceGroup` and `totalResourceWithinResourceGroup`, wrapped in `BAIBoardItemErrorBoundary` + `Suspense`. Invitation badge click routes to `/data?invitation=true` through `useWebUINavigate`. - Refactored `StorageStatusPanelCard` to follow the Dashboard board-item pattern used by `MyResource` / `MyResourceWithinResourceGroup`: - Root is a `BAIFlex direction="column" align="stretch"` with `paddingInline: token.paddingXL` and `paddingBottom: token.padding`. - Title uses the shared `BAIBoardItemTitle`, which reserves space for the board's drag handle. Wrapping in a `BAICard` caused the title to overlap the handle on the left edge — that's fixed. - Props type: `BAICardProps` → `BAIFlexProps`. ## V2 migration notes (TODOs left in `StorageStatusPanelCard.tsx`) The status counts still run off the legacy REST call `baiClient.vfolder.list()` and the V1 `user_resource_policy` / `project_resource_policy` GraphQL root fields. TODOs in the file call out the V2 rewrite with explicit scoping rules: - **ProjectFolders**: when ported to `projectVfolders(projectId: …)`, it must be scoped to the project currently selected in the global header project selector (`currentProject.id`), not aggregated across every project the user can see. - **InvitedFolders**: migration deferred. The V2 `VFolderFilter` does not yet expose an "invited only / received share" predicate, so we cannot reproduce the current `!is_owner && ownership_type === 'user'` filter with a single server-side count. Stays on legacy REST until the backend adds the filter field; revisit in a follow-up issue. ## Internationalization Added `data.usage.Unknown` to all 21 locales under `resources/i18n/`, placed alphabetically between `StatusOfSelectedHost` and `Used` in the `data.usage` object. The key powers the tooltip fallback when a host has `usage: {}` (object present, `percentage` missing). `packages/backend.ai-ui/src/locale/*.json` is intentionally untouched — that package does not consume the key. ## Testing - `bash scripts/verify.sh` — Relay, Lint, Format, TypeScript all pass on this branch and on every descendant branch in the stack (FR-2573, FR-2619, FR-2685, FR-2688). - Manually verified against a manager response where every volume reports `usage: {}` (no `percentage`): per-row neutral badges render with `Host Status: Unknown` tooltip; header `?` icon appears because `icn02:flash01` / `seoul-h100:flash0*` advertise `"quota"` in capabilities; clicking it opens the modal pre-selected on the first quota-capable host. **Checklist:** (if applicable) - [ ] Documentation - [ ] Minimum required manager version - [ ] Specific setting for review (eg., KB link, endpoint or how to setup) - [ ] Minimum requirements to check during review - [ ] Test case(s) to demonstrate the difference of before/after
99b663c to
7c822bb
Compare
f1aff6a to
687147d
Compare

resolves #6937 (FR-2691)
Summary
Clears the three header panels that used to sit above the folder table on
/data, redistributes their responsibilities, and reshapes the "Location" column into a "Host" column that surfaces per-volume capacity info without requiring an extra click on every row.Changes on
/data(VFolderNodeListPage.tsx)Rowthat rendered the Create Folder action card,StorageStatusPanelCard, andQuotaPerStorageVolumePanelCard. The Create Folder affordance is already present as the primary button inside the folder table card header, so no replacement action card is needed.ActionItemContent,BAINewFolderIcon,BAIAlertIconWithTooltip,Grid.useBreakpoint,useWebUINavigate,ErrorBoundary, per-rowSuspense,CARD_MIN_HEIGHT).Changes in the folder table (
VFolderNodesV2.tsx)title:data.folders.Location(위치) →data.Host(호스트).BAIAlertIconWithTooltipsits next to the "Host" label. Clicking it opens theQuotaPerStorageVolumePanelCardin a Modal, pre-selected on a quota-supporting host. The icon is hidden entirely when no volume reports"quota"incapabilities, so the modal entry point disappears when the feature is unusable — we don't open a dialog with no useful content.VFolderHostCellrenders aStorageUsageBadge(sourced fromvfolder.list_hosts(), cached under the shared['vhostInfo']tan-query key thatStorageSelectalready uses) plus the host name. No per-cell click behavior — the modal is only reachable via the column-header affordance.StorageSelect's own precedent: the badge renders whenever the backend attaches ausageobject (even{}).StorageUsageBadgeresolves apercentage-lessusageto a neutral (uncolored) marker. The accompanying tooltip readsHost Status: <Adequate | Caution | Insufficient | Unknown>; theUnknownlabel is a newly added key that covers the "backend reports no percentage" case.useSuspenseTanQuerytouseTanQuery. A per-cell Suspense boundary whose fallback rendered the bare host text (visually indistinguishable from the "loaded but no usage data" branch) caused rows to stick in the fallback even aftervhostInforesolved.Changes to
QuotaPerStorageVolumePanelCard.tsxBAICardwrapper and the internal title. The consumer is now aModalthat supplies its own title and chrome, and a nested card here produced a duplicated header on top of the modal frame.?tooltip icon (QuestionCircleOutlinedwithdata.HostDetails) into the Modal title so all header affordances live in one place.StorageSelectmoved out of the former card'sextraslot (right-aligned, borderless) and into the modal body as the first element, left-aligned with a sensibleminWidth.defaultVolumeInfo?: VolumeInfoprop. When set, the card seedsselectedVolumeInfowith that value and disables the built-inautoSelectType="usage"fallback; users can still switch volumes through the inlineStorageSelect. This is how the header icon pre-selects a quota-supporting host.BAICardProps→ a dedicated local interface (card-specific passthrough props no longer make sense).Changes on the Dashboard (
DashboardPage.tsx,StorageStatusPanelCard.tsx)folderStatusboard item betweenmyResourceWithinResourceGroupandtotalResourceWithinResourceGroup, wrapped inBAIBoardItemErrorBoundary+Suspense. Invitation badge click routes to/data?invitation=truethroughuseWebUINavigate.StorageStatusPanelCardto follow the Dashboard board-item pattern used byMyResource/MyResourceWithinResourceGroup:BAIFlex direction="column" align="stretch"withpaddingInline: token.paddingXLandpaddingBottom: token.padding.BAIBoardItemTitle, which reserves space for the board's drag handle. Wrapping in aBAICardcaused the title to overlap the handle on the left edge — that's fixed.BAICardProps→BAIFlexProps.V2 migration notes (TODOs left in
StorageStatusPanelCard.tsx)The status counts still run off the legacy REST call
baiClient.vfolder.list()and the V1user_resource_policy/project_resource_policyGraphQL root fields. TODOs in the file call out the V2 rewrite with explicit scoping rules:projectVfolders(projectId: …), it must be scoped to the project currently selected in the global header project selector (currentProject.id), not aggregated across every project the user can see.VFolderFilterdoes not yet expose an "invited only / received share" predicate, so we cannot reproduce the current!is_owner && ownership_type === 'user'filter with a single server-side count. Stays on legacy REST until the backend adds the filter field; revisit in a follow-up issue.Internationalization
Added
data.usage.Unknownto all 21 locales underresources/i18n/, placed alphabetically betweenStatusOfSelectedHostandUsedin thedata.usageobject. The key powers the tooltip fallback when a host hasusage: {}(object present,percentagemissing).packages/backend.ai-ui/src/locale/*.jsonis intentionally untouched — that package does not consume the key.Testing
bash scripts/verify.sh— Relay, Lint, Format, TypeScript all pass on this branch and on every descendant branch in the stack (FR-2573, FR-2619, FR-2685, FR-2688).usage: {}(nopercentage): per-row neutral badges render withHost Status: Unknowntooltip; header?icon appears becauseicn02:flash01/seoul-h100:flash0*advertise"quota"in capabilities; clicking it opens the modal pre-selected on the first quota-capable host.Checklist: (if applicable)