-
Notifications
You must be signed in to change notification settings - Fork 78
feat(FR-1694): Create a new agent page using the agent_nodes query
#4665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
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
|
St.❔ |
Category | Percentage | Covered / Total |
|---|---|---|---|
| 🔴 | Statements | 4.39% (-0.02% 🔻) |
522/11892 |
| 🔴 | Branches | 3.51% (-0.09% 🔻) |
297/8460 |
| 🔴 | Functions | 2.56% (-0.01% 🔻) |
93/3638 |
| 🔴 | Lines | 4.37% (-0.02% 🔻) |
508/11631 |
Show new covered files 🐣
St.❔ |
File | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
| 🔴 | ... / AgentSettingModalLegacy.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / AgentNodes.tsx |
0% | 0% | 0% | 0% |
| 🔴 | ... / AgentNodesListPage.tsx |
0% | 0% | 0% | 0% |
Test suite run success
118 tests passing in 13 suites.
Report generated by 🧪jest coverage report action from f0dbf10
901d66d to
78cd18c
Compare
fc160a3 to
097a609
Compare
097a609 to
e9ef843
Compare
78cd18c to
a47b498
Compare
a47b498 to
bcb77ed
Compare
bcb77ed to
15919cf
Compare
Coverage report for
|
St.❔ |
Category | Percentage | Covered / Total |
|---|---|---|---|
| 🔴 | Statements | 52.52% (-2.27% 🔻) |
167/318 |
| 🔴 | Branches | 31.53% (-1.22% 🔻) |
93/295 |
| 🔴 | Functions | 41.89% (-0.57% 🔻) |
31/74 |
| 🔴 | Lines | 54.51% (-2.31% 🔻) |
151/277 |
Show files with reduced coverage 🔻
St.❔ |
File | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
| 🟡 | helper/index.ts | 58.71% (-5.58% 🔻) |
41.92% (-2.96% 🔻) |
57.14% (-2.12% 🔻) |
62.2% (-6.22% 🔻) |
Test suite run success
62 tests passing in 4 suites.
Report generated by 🧪jest coverage report action from f0dbf10
9133122 to
a9b6b9d
Compare
There was a problem hiding this 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 creates a new agent nodes list page using the agent_nodes GraphQL query to replace the legacy AgentList component. The implementation introduces a modern agent management interface with improved filtering, sorting, and column customization capabilities.
Key Changes:
- New
AgentNodesListPagecomponent with GraphQL query integration using Relay - New
AgentNodestable component with comprehensive agent data display - Addition of
parseObjectMaphelper function for safe JSON parsing - New internationalization keys for agent-related UI text
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| react/src/pages/AgentNodesListPage.tsx | New page component implementing agent nodes list with filtering, sorting, and pagination using GraphQL agent_nodes query |
| react/src/components/AgentNodes.tsx | New comprehensive table component displaying agent details including status, allocation, utilization, and metadata |
| react/src/pages/ResourcesPage.tsx | Updated to use new AgentNodesListPage instead of legacy AgentList component |
| resources/i18n/en.json | Added new translation keys for agent-related UI elements (AgentVersion, AntiMining, Guard, Containers, etc.) |
| resources/i18n/ko.json | Partially updated Korean translations with some keys left empty |
| packages/backend.ai-ui/src/helper/index.ts | Added parseObjectMap utility function for safely parsing unknown inputs into object records |
| { | ||
| key: 'gpu_alloc_map', | ||
| dataIndex: 'gpu_alloc_map', | ||
| title: 'GPU Allocation Map', |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard-coded text "GPU Allocation Map" should use i18n function. According to internationalization guidelines, all user-facing text must use i18n functions. Use t('agent.GPUAllocationMap') instead and add the translation key to the i18n files.
| gap="xxs" | ||
| > | ||
| <BAIText> | ||
| {statKey === 'net_rx' ? 'Net Rx' : 'Net Tx'} |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard-coded text "Net Rx" and "Net Tx" should use i18n functions. According to internationalization guidelines, all user-facing text must use i18n functions. Consider using t('agent.NetRx') and t('agent.NetTx') instead and add the translation keys to the i18n files.
| "AgentVersion": "Agent Version", | ||
| "Allocation": "Allocation", | ||
| "AntiMining": "Anti Mining", | ||
| "Architecture": "Architecture", | ||
| "AutoRefreshEvery5s": "Auto refresh every 5s", | ||
| "AutoTerminateAbusingKernel": "Auto Terminate Abusing Kernel", | ||
| "BackendType": "Backend Type", | ||
| "Capabilities": "Capabilities", | ||
| "ComputePlugins": "Compute Plugins", | ||
| "Connected": "Connected", | ||
| "Containers": "Containers", | ||
| "DetailedInformation": "Detailed Information", | ||
| "DiskPerc": "Disk %", | ||
| "Endpoint": "Endpoint", | ||
| "Guard": "Guard", | ||
| "HardwareMetadata": "Hardware Metadata", | ||
| "LostAt": "Lost At", | ||
| "Maintaining": "Maintaining", | ||
| "NoAgentToDisplay": "No Agents to display", | ||
| "NoAvailableLiveStat": "No available live stat", | ||
| "NoChanges": "No changes.", | ||
| "NoNetworkSignal": "No network signals.", | ||
| "Permissions": "Permissions", | ||
| "Region": "Region", | ||
| "Resources": "Resources", | ||
| "Running": "Running", | ||
| "Schedulable": "Schedulable", | ||
| "Specs": "Specs", | ||
| "Starts": "Starts", | ||
| "Status": "Status", | ||
| "StatusChanged": "Status Changed", | ||
| "Terminated": "Terminated", | ||
| "Utilization": "Utilization" | ||
| "Utilization": "Utilization", | ||
| "Version": "Version" |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple new translation keys added in the English file (AgentVersion, AntiMining, AutoTerminateAbusingKernel, ComputePlugins, Guard, HardwareMetadata, LostAt, Permissions, Specs, StatusChanged, Version) are missing from other language files (ko.json, ja.json, zh-CN.json, zh-TW.json, etc.). According to i18n guidelines, all translation keys must be provided for all supported languages. Please add corresponding translations to all language files.
| {agent_nodes ? ( | ||
| <AgentNodes | ||
| agentsFrgmt={ | ||
| _.map(agent_nodes.edges, (e) => e?.node).filter(Boolean) as any |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using as any type assertion bypasses TypeScript's type safety. Consider defining a proper type or using a type guard to safely convert the filtered nodes to the expected type. This could hide potential runtime errors.
| <BAIPropertyFilter | ||
| // TODO: support date filter (status_changed, first_contact, lost_at) | ||
| filterProperties={[ | ||
| { key: 'id', propertyLabel: 'ID', type: 'string' }, |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard-coded text "ID" should use i18n function. According to internationalization guidelines, all user-facing text must use i18n functions. Use t('general.ID') or similar translation key instead.
| "AgentSetting": "에이전트 설정", | ||
| "AgentSettingUpdated": "에이전트 설정이 변경되었습니다.", | ||
| "Allocation": "할당 정보", | ||
| "AntiMining": "", |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing translation for "AntiMining". The value is an empty string ("") while other languages like English have "Anti Mining". According to i18n guidelines, all user-facing text must have translations.
| "DetailedInformation": "상세 정보", | ||
| "DiskPerc": "디스크 %", | ||
| "Endpoint": "엔드포인트", | ||
| "Guard": "", |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing translation for "Guard". The value is an empty string ("") while other languages like English have "Guard". According to i18n guidelines, all user-facing text must have translations.
| onChangeOrder, | ||
| ...tableProps | ||
| }) => { | ||
| 'use memo'; |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unknown directive: 'use memo'.
| */ | ||
| export function parseObjectMap<T = any>(raw: unknown): Record<string, T> { | ||
| if (!raw) return {}; | ||
| if (typeof raw === 'object' && raw !== null && !Array.isArray(raw)) { |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable 'raw' is of type date, object or regular expression, but it is compared to an expression of type null.
| if (typeof raw === 'object' && raw !== null && !Array.isArray(raw)) { | |
| if ( | |
| typeof raw === 'object' && | |
| raw !== null && | |
| !Array.isArray(raw) && | |
| (Object.getPrototypeOf(raw) === Object.prototype || Object.getPrototypeOf(raw) === null) | |
| ) { |
a9b6b9d to
f0dbf10
Compare

resolves #NNN (FR-MMM)
Checklist: (if applicable)