Skip to content

Commit 2f3fab9

Browse files
committed
feat(FR-1400): Improved Kernel Identification with Hostname (#4176)
# Improved Kernel Identification with Hostname Display ## Summary This PR replaces the kernel "role" display with "hostname" in kernel lists to provide better identification for users. When there are dozens of sub kernels, showing only the role (main/sub) becomes confusing as users cannot distinguish between different kernels. ## Changes Made - **ConnectedKernelList.tsx**: Updated GraphQL fragment to fetch `cluster_hostname` instead of `cluster_role` and changed column title from "Role" to "Hostname" - **ContainerLogModal.tsx**: Modified kernel selection to display hostname instead of role+index combination - Added "Container Logs" title to the log modal - Improved component structure by using `BAIUnmountAfterClose` for log modals - Reorganized kernel list columns for better readability - Added `useMemo` for sorting kernels by hostname - **i18n files**: Added "Hostname", "Kernel", and "ContainerLogs" translation keys across all supported languages ## Technical Details - Replaced GraphQL field `cluster_role` with `cluster_hostname` in kernel queries - Updated React components to use the new hostname field for display - Removed unnecessary wrapper components and improved component structure - Added log button directly to the hostname column for better UX - Improved kernel ID display in the container log modal ## Testing - Verify kernel list displays hostnames instead of roles - Check that kernel selection in container logs shows meaningful hostnames - Confirm all UI text is properly translated This change improves user experience by providing more meaningful identification information, especially in multi-kernel environments where role-based identification is insufficient.
1 parent d1755b7 commit 2f3fab9

25 files changed

+150
-85
lines changed

react/src/components/ComputeSessionNodeItems/ConnectedKernelList.tsx

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ import {
1212
filterOutEmpty,
1313
filterOutNullAndUndefined,
1414
BAITable,
15-
BAIFlex,
1615
BAIUnmountAfterClose,
1716
} from 'backend.ai-ui';
1817
import _ from 'lodash';
1918
import { ScrollTextIcon } from 'lucide-react';
20-
import { useState } from 'react';
19+
import { useMemo, useState } from 'react';
2120
import { useTranslation } from 'react-i18next';
2221
import { graphql, useFragment } from 'react-relay';
2322

@@ -66,6 +65,8 @@ const ConnectedKernelList: React.FC<ConnectedKernelListProps> = ({
6665
fragment ConnectedKernelListFragment on KernelNode @relay(plural: true) {
6766
id
6867
row_id
68+
cluster_hostname
69+
cluster_idx
6970
cluster_role
7071
status
7172
status_info
@@ -78,36 +79,30 @@ const ConnectedKernelList: React.FC<ConnectedKernelListProps> = ({
7879

7980
const columns = filterOutEmpty<ColumnType<Kernel>>([
8081
{
81-
title: t('kernel.KernelId'),
82-
fixed: 'left',
83-
dataIndex: 'row_id',
84-
render: (row_id) => (
85-
<>
86-
<Typography.Text copyable ellipsis>
87-
{row_id}
88-
</Typography.Text>
89-
<Tooltip title={t('session.SeeContainerLogs')}>
90-
<Button
91-
icon={<ScrollTextIcon />}
92-
type="link"
93-
onClick={() => {
94-
setKernelIdForLogModal(row_id);
95-
}}
96-
style={{
97-
width: 'auto',
98-
height: 'auto',
99-
marginInlineStart: token.marginXXS,
100-
border: 'none',
101-
}}
102-
/>
103-
</Tooltip>
104-
</>
105-
),
106-
},
107-
{
108-
title: t('kernel.Role'),
109-
dataIndex: 'cluster_role',
110-
render: (role) => <Tag>{role}</Tag>,
82+
title: t('kernel.Hostname'),
83+
dataIndex: 'cluster_hostname',
84+
render: (hostname, record) => {
85+
return (
86+
<>
87+
<Typography.Text>{hostname}</Typography.Text>
88+
<Tooltip title={t('session.SeeContainerLogs')}>
89+
<Button
90+
icon={<ScrollTextIcon />}
91+
type="link"
92+
onClick={() => {
93+
record.row_id && setKernelIdForLogModal(record.row_id);
94+
}}
95+
style={{
96+
width: 'auto',
97+
height: 'auto',
98+
marginInlineStart: token.marginXXS,
99+
border: 'none',
100+
}}
101+
/>
102+
</Tooltip>
103+
</>
104+
);
105+
},
111106
},
112107
{
113108
title: t('kernel.Status'),
@@ -135,6 +130,23 @@ const ConnectedKernelList: React.FC<ConnectedKernelListProps> = ({
135130
);
136131
},
137132
},
133+
{
134+
title: t('kernel.AgentId'),
135+
dataIndex: 'agent_id',
136+
render: (id) => <Typography.Text copyable>{id}</Typography.Text>,
137+
},
138+
{
139+
title: t('kernel.KernelId'),
140+
fixed: 'left',
141+
dataIndex: 'row_id',
142+
render: (row_id) => (
143+
<>
144+
<Typography.Text copyable ellipsis>
145+
{row_id}
146+
</Typography.Text>
147+
</>
148+
),
149+
},
138150
{
139151
title: t('kernel.ContainerId'),
140152
dataIndex: 'container_id',
@@ -150,15 +162,16 @@ const ConnectedKernelList: React.FC<ConnectedKernelListProps> = ({
150162
</Typography.Text>
151163
),
152164
},
153-
{
154-
title: t('kernel.AgentId'),
155-
dataIndex: 'agent_id',
156-
render: (id) => <Typography.Text copyable>{id}</Typography.Text>,
157-
},
158165
]);
159166

167+
const sortedKernels = useMemo(() => {
168+
return _.orderBy(filterOutNullAndUndefined(kernelNodes), [
169+
'cluster_role',
170+
'cluster_idx',
171+
] as Array<keyof Kernel>);
172+
}, [kernelNodes]);
160173
return (
161-
<BAIFlex direction="column" align="stretch" gap={'sm'}>
174+
<>
162175
{/* TODO: implement filter when compute_session_node query supports filter */}
163176
{/* <BAIPropertyFilter
164177
filterProperties={[
@@ -181,9 +194,7 @@ const ConnectedKernelList: React.FC<ConnectedKernelListProps> = ({
181194
rowKey="id"
182195
scroll={{ x: 'max-content' }}
183196
columns={columns}
184-
dataSource={filterOutNullAndUndefined(kernelNodes)}
185-
style={{ width: '100%' }}
186-
// TODO: implement pagination when compute_session_node query supports pagination
197+
dataSource={sortedKernels} // TODO: implement pagination when compute_session_node query supports pagination
187198
/>
188199

189200
<BAIUnmountAfterClose>
@@ -196,7 +207,7 @@ const ConnectedKernelList: React.FC<ConnectedKernelListProps> = ({
196207
}}
197208
/>
198209
</BAIUnmountAfterClose>
199-
</BAIFlex>
210+
</>
200211
);
201212
};
202213

react/src/components/ComputeSessionNodeItems/ContainerLogModal.tsx

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ContainerLogModalFragment$key } from '../../__generated__/ContainerLogModalFragment.graphql';
22
import { downloadBlob } from '../../helper/csv-util';
33
import { useSuspendedBackendaiClient } from '../../hooks';
4-
import { useCurrentUserRole } from '../../hooks/backendai';
54
import { useTanQuery } from '../../hooks/reactQueryAlias';
65
import { useMemoWithPrevious } from '../../hooks/useMemoWithPrevious';
76
import BAIModal, { BAIModalProps } from '../BAIModal';
@@ -12,7 +11,7 @@ import { Button, Divider, Grid, theme, Tooltip, Typography } from 'antd';
1211
import { BAIFlex } from 'backend.ai-ui';
1312
import _ from 'lodash';
1413
import { DownloadIcon } from 'lucide-react';
15-
import React, { useEffect, useState } from 'react';
14+
import React, { useState } from 'react';
1615
import { useTranslation } from 'react-i18next';
1716
import { graphql, useFragment } from 'react-relay';
1817

@@ -28,7 +27,6 @@ const ContainerLogModal: React.FC<ContainerLogModalProps> = ({
2827
}) => {
2928
const baiClient = useSuspendedBackendaiClient();
3029
const { token } = theme.useToken();
31-
const userRole = useCurrentUserRole();
3230

3331
const session = useFragment(
3432
graphql`
@@ -46,6 +44,7 @@ const ContainerLogModal: React.FC<ContainerLogModalProps> = ({
4644
container_id
4745
cluster_idx
4846
cluster_role
47+
cluster_hostname
4948
}
5049
}
5150
}
@@ -61,14 +60,6 @@ const ContainerLogModal: React.FC<ContainerLogModalProps> = ({
6160
kernelNodes[0]?.row_id,
6261
);
6362

64-
useEffect(() => {
65-
if (modalProps.open === false) {
66-
setSelectedKernelId(undefined);
67-
}
68-
}, [modalProps.open]);
69-
70-
// Currently we can only fetch full logs
71-
// const [logSize, setLogSize] = useState<100|'full'>('full');
7263
const {
7364
data: logs,
7465
refetch,
@@ -110,7 +101,7 @@ const ContainerLogModal: React.FC<ContainerLogModalProps> = ({
110101
title={
111102
<BAIFlex style={{ maxWidth: '100%' }} gap={'sm'}>
112103
<Typography.Title level={4} style={{ margin: 0, flexShrink: 0 }}>
113-
Logs
104+
{t('kernel.ContainerLogs')}
114105
</Typography.Title>
115106
{session ? (
116107
<>
@@ -153,7 +144,6 @@ const ContainerLogModal: React.FC<ContainerLogModalProps> = ({
153144
gap={'sm'}
154145
>
155146
<BAIFlex gap="sm" wrap="wrap">
156-
Kernel Role
157147
<BAISelect
158148
value={selectedKernelId}
159149
onChange={(value) => {
@@ -167,21 +157,16 @@ const ContainerLogModal: React.FC<ContainerLogModalProps> = ({
167157
return {
168158
label: (
169159
<>
170-
{e?.node?.cluster_role}
171-
{e?.node?.cluster_role !== 'main'
172-
? e?.node?.cluster_idx
173-
: ''}
174-
{userRole === 'admin' || userRole === 'superadmin' ? (
175-
<Typography.Text
176-
style={{
177-
fontFamily: 'monospace',
178-
fontSize: token.fontSizeSM,
179-
}}
180-
type="secondary"
181-
>
182-
({(e?.node?.row_id || '').substring(0, 5)})
183-
</Typography.Text>
184-
) : null}
160+
{e?.node?.cluster_hostname}
161+
<Typography.Text
162+
style={{
163+
fontFamily: 'monospace',
164+
fontSize: token.fontSizeSM,
165+
}}
166+
type="secondary"
167+
>
168+
({(e?.node?.row_id || '').substring(0, 5)})
169+
</Typography.Text>
185170
</>
186171
),
187172
value: e?.node?.row_id,

react/src/components/ComputeSessionNodeItems/ContainerLogModalWithLazyQueryLoader.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ContainerLogModalWithLazyQueryLoaderQuery } from '../../__generated__/ContainerLogModalWithLazyQueryLoaderQuery.graphql';
22
import { useCurrentProjectValue } from '../../hooks/useCurrentProject';
33
import ContainerLogModal from './ContainerLogModal';
4+
import { BAIUnmountAfterClose } from 'backend.ai-ui';
45
import { graphql, useLazyLoadQuery } from 'react-relay';
56

67
const ContainerLogModalWithLazyQueryLoader: React.FC<{
@@ -32,14 +33,16 @@ const ContainerLogModalWithLazyQueryLoader: React.FC<{
3233
);
3334

3435
return (
35-
<ContainerLogModal
36-
sessionFrgmt={compute_session_node || null}
37-
open={open}
38-
loading={loading}
39-
onCancel={() => {
40-
onRequestClose && onRequestClose();
41-
}}
42-
/>
36+
<BAIUnmountAfterClose>
37+
<ContainerLogModal
38+
sessionFrgmt={compute_session_node || null}
39+
open={open}
40+
loading={loading}
41+
onCancel={() => {
42+
onRequestClose && onRequestClose();
43+
}}
44+
/>
45+
</BAIUnmountAfterClose>
4346
);
4447
};
4548

react/src/components/ComputeSessionNodeItems/SessionActionButtons.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
BAISessionLogIcon,
1717
BAITerminalAppIcon,
1818
BAITerminateIcon,
19+
BAIUnmountAfterClose,
1920
} from 'backend.ai-ui';
2021
import _ from 'lodash';
2122
import { Suspense, useState } from 'react';
@@ -125,13 +126,15 @@ const SessionActionButtons: React.FC<SessionActionButtonsProps> = (props) => {
125126
}}
126127
/>
127128
</Tooltip>
128-
<ContainerLogModal
129-
sessionFrgmt={session}
130-
open={openLogModal}
131-
onCancel={() => {
132-
setOpenLogModal(false);
133-
}}
134-
/>
129+
<BAIUnmountAfterClose>
130+
<ContainerLogModal
131+
sessionFrgmt={session}
132+
open={openLogModal}
133+
onCancel={() => {
134+
setOpenLogModal(false);
135+
}}
136+
/>
137+
</BAIUnmountAfterClose>
135138
<Tooltip title={t('session.RequestContainerCommit')}>
136139
<Button
137140
disabled={

resources/i18n/de.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,9 @@
776776
"kernel": {
777777
"AgentId": "Agenten -ID",
778778
"ContainerId": "Container -ID",
779+
"ContainerLogs": "Containerprotokolle",
780+
"Hostname": "Hostname",
781+
"Kernel": "Kernel",
779782
"KernelId": "Kernel ID",
780783
"Kernels": "Kerne",
781784
"Role": "Rolle",

resources/i18n/el.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,9 @@
772772
"kernel": {
773773
"AgentId": "Αναγνωριστικό πράκτορα",
774774
"ContainerId": "Αναγνωριστικό δοχείου",
775+
"ContainerLogs": "Αρχεία καταγραφής εμπορευματοκιβωτίων",
776+
"Hostname": "Όνομα κεντρικού υπολογιστή",
777+
"Kernel": "Πυρήνας",
775778
"KernelId": "Αναγνωριστικό πυρήνα",
776779
"Kernels": "Πυρήνες",
777780
"Role": "Ρόλος",

resources/i18n/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,9 @@
780780
"kernel": {
781781
"AgentId": "Agent ID",
782782
"ContainerId": "Container ID",
783+
"ContainerLogs": "Container Logs",
784+
"Hostname": "Hostname",
785+
"Kernel": "Kernel",
783786
"KernelId": "Kernel ID",
784787
"Kernels": "Kernels",
785788
"Role": "Role",

resources/i18n/es.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,9 @@
776776
"kernel": {
777777
"AgentId": "ID de agente",
778778
"ContainerId": "ID de contenedor",
779+
"ContainerLogs": "Registros de contenedores",
780+
"Hostname": "Nombre de host",
781+
"Kernel": "Núcleo",
779782
"KernelId": "ID de núcleo",
780783
"Kernels": "Núcleo",
781784
"Role": "Role",

resources/i18n/fi.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,9 @@
776776
"kernel": {
777777
"AgentId": "Agenttitunnus",
778778
"ContainerId": "Konttitunnus",
779+
"ContainerLogs": "Säiliölokit",
780+
"Hostname": "Isäntänimi",
781+
"Kernel": "Ytimen",
779782
"KernelId": "Ytimen tunnus",
780783
"Kernels": "Ytimet",
781784
"Role": "Rooli",

resources/i18n/fr.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,9 @@
776776
"kernel": {
777777
"AgentId": "ID d'agent",
778778
"ContainerId": "ID de conteneur",
779+
"ContainerLogs": "Journaux des conteneurs",
780+
"Hostname": "Nom d'hôte",
781+
"Kernel": "Noyau",
779782
"KernelId": "ID du noyau",
780783
"Kernels": "Graines",
781784
"Role": "Rôle",

0 commit comments

Comments
 (0)