Skip to content

Commit 265ffc3

Browse files
committed
feat: Reservoir Audit log UI draft
1 parent be55c1b commit 265ffc3

File tree

7 files changed

+656
-161
lines changed

7 files changed

+656
-161
lines changed

react/craco.config.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ module.exports = {
2424
'../resources/**/*',
2525
],
2626
};
27-
27+
2828
// Override deprecated middleware options with setupMiddlewares
2929
const originalOnBefore = devServerConfig.onBeforeSetupMiddleware;
3030
const originalOnAfter = devServerConfig.onAfterSetupMiddleware;
31-
31+
3232
if (originalOnBefore || originalOnAfter) {
3333
delete devServerConfig.onBeforeSetupMiddleware;
3434
delete devServerConfig.onAfterSetupMiddleware;
35-
35+
3636
devServerConfig.setupMiddlewares = (middlewares, devServer) => {
3737
if (originalOnBefore) {
3838
originalOnBefore(devServer);
@@ -43,7 +43,7 @@ module.exports = {
4343
return middlewares;
4444
};
4545
}
46-
46+
4747
return devServerConfig;
4848
},
4949
babel: {

react/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,9 +467,9 @@ const router = createBrowserRouter([
467467
<BAIErrorBoundary>
468468
<Suspense
469469
fallback={
470-
<Flex direction="column" style={{ maxWidth: 700 }}>
470+
<BAIFlex direction="column" style={{ maxWidth: 700 }}>
471471
<Skeleton active />
472-
</Flex>
472+
</BAIFlex>
473473
}
474474
>
475475
<ReservoirPage />

react/src/components/ReservoirArtifactDetail.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
Divider,
2323
theme,
2424
} from 'antd';
25-
import { Flex } from 'backend.ai-ui';
25+
import { BAIFlex } from 'backend.ai-ui';
2626
import dayjs from 'dayjs';
2727
import relativeTime from 'dayjs/plugin/relativeTime';
2828
import { ArrowLeft, Download, Info, CheckCircle } from 'lucide-react';
@@ -88,7 +88,7 @@ const ReservoirArtifactDetail: React.FC<ReservoirArtifactDetailProps> = ({
8888

8989
return (
9090
<div>
91-
<Flex align="center" style={{ marginBottom: token.marginLG }}>
91+
<BAIFlex align="center" style={{ marginBottom: token.marginLG }}>
9292
<Button
9393
type="text"
9494
icon={<ArrowLeft size={18} />}
@@ -98,7 +98,7 @@ const ReservoirArtifactDetail: React.FC<ReservoirArtifactDetailProps> = ({
9898
type="vertical"
9999
style={{ marginLeft: 0, marginRight: token.marginMD }}
100100
/>
101-
<Flex align="center" gap="xs">
101+
<BAIFlex align="center" gap="xs">
102102
<Title level={3} style={{ margin: 0 }}>
103103
{artifact.name}
104104
</Title>
@@ -112,8 +112,8 @@ const ReservoirArtifactDetail: React.FC<ReservoirArtifactDetailProps> = ({
112112
>
113113
{artifact.status.toUpperCase()}
114114
</Tag>
115-
</Flex>
116-
</Flex>
115+
</BAIFlex>
116+
</BAIFlex>
117117

118118
{renderPullingProgress()}
119119

@@ -214,15 +214,15 @@ const ReservoirArtifactDetail: React.FC<ReservoirArtifactDetailProps> = ({
214214
key: 'version',
215215
render: (version: string, record: any) => (
216216
<div>
217-
<Flex align="center" gap="xs">
217+
<BAIFlex align="center" gap="xs">
218218
<BAIText strong>{version}</BAIText>
219219
{record.isLatest && <Tag color="blue">LATEST</Tag>}
220220
{record.isInstalled && (
221221
<Tag color="green" icon={<CheckCircle size={12} />}>
222222
INSTALLED
223223
</Tag>
224224
)}
225-
</Flex>
225+
</BAIFlex>
226226
{record.checksum && (
227227
<Typography.Text
228228
type="secondary"

react/src/components/ReservoirArtifactList.tsx

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ import {
77
} from '../utils/reservoir';
88
import BAIText from './BAIText';
99
import {
10-
Table,
1110
Button,
1211
Tag,
1312
Typography,
1413
Tooltip,
1514
TableColumnsType,
1615
theme,
1716
} from 'antd';
18-
import { Flex } from 'backend.ai-ui';
17+
import { BAIFlex, BAITable } from 'backend.ai-ui';
1918
import dayjs from 'dayjs';
2019
import relativeTime from 'dayjs/plugin/relativeTime';
2120
import { Download } from 'lucide-react';
@@ -66,9 +65,9 @@ const ReservoirArtifactList: React.FC<ReservoirArtifactListProps> = ({
6665
dataIndex: 'name',
6766
key: 'name',
6867
render: (name: string, record: ReservoirArtifact) => (
69-
<Flex align="center" gap="sm">
68+
<BAIFlex align="center" gap="sm">
7069
<div>
71-
<Flex gap={'xs'}>
70+
<BAIFlex gap={'xs'}>
7271
<Link
7372
to={'/reservoir/' + record.id}
7473
style={{
@@ -90,7 +89,7 @@ const ReservoirArtifactList: React.FC<ReservoirArtifactListProps> = ({
9089
>
9190
{getTypeIcon(record.type, 14)} {record.type.toUpperCase()}
9291
</Tag>
93-
</Flex>
92+
</BAIFlex>
9493
{record.description && (
9594
<Typography.Text
9695
type="secondary"
@@ -100,7 +99,7 @@ const ReservoirArtifactList: React.FC<ReservoirArtifactListProps> = ({
10099
</Typography.Text>
101100
)}
102101
</div>
103-
</Flex>
102+
</BAIFlex>
104103
),
105104
sorter: onChangeOrder ? true : false,
106105
// sortOrder:
@@ -143,7 +142,7 @@ const ReservoirArtifactList: React.FC<ReservoirArtifactListProps> = ({
143142
key: 'status',
144143
render: (status: ReservoirArtifact['status'], record) => (
145144
// <Tag color={getStatusColor(status)} icon={getStatusIcon(status)}>
146-
<Flex>
145+
<BAIFlex>
147146
<Tag
148147
icon={getStatusIcon(status)}
149148
color={getStatusColor(status)}
@@ -169,7 +168,7 @@ const ReservoirArtifactList: React.FC<ReservoirArtifactListProps> = ({
169168
/>
170169
</Tooltip>
171170
)}
172-
</Flex>
171+
</BAIFlex>
173172
),
174173
// width: '12%',
175174
},
@@ -215,28 +214,28 @@ const ReservoirArtifactList: React.FC<ReservoirArtifactListProps> = ({
215214
},
216215
];
217216

218-
const handleTableChange = (
219-
paginationInfo: any,
220-
filters: any,
221-
sorter: any,
222-
) => {
223-
if (onChangeOrder && sorter.field) {
224-
const order =
225-
sorter.order === 'ascend' ? sorter.field : `-${sorter.field}`;
226-
onChangeOrder(order);
227-
}
228-
};
217+
// const handleTableChange = (
218+
// paginationInfo: any,
219+
// filters: any,
220+
// sorter: any,
221+
// ) => {
222+
// if (onChangeOrder && sorter.field) {
223+
// const order =
224+
// sorter.order === 'ascend' ? sorter.field : `-${sorter.field}`;
225+
// onChangeOrder(order);
226+
// }
227+
// };
229228

230229
return (
231-
<Table
230+
<BAITable
231+
resizable
232232
columns={columns}
233233
dataSource={artifacts}
234234
rowKey="id"
235235
loading={loading}
236236
pagination={pagination}
237237
rowSelection={rowSelection}
238-
onChange={handleTableChange}
239-
size="middle"
238+
size="small"
240239
scroll={{ x: 'max-content' }}
241240
onRow={(record) => ({
242241
onClick: (event) => {
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import type { ReservoirAuditLog } from '../types/reservoir';
2+
import BAIPropertyFilter from './BAIPropertyFilter';
3+
import BAIText from './BAIText';
4+
import { Tag, Typography } from 'antd';
5+
import { BAIFlex, BAITable } from 'backend.ai-ui';
6+
import dayjs from 'dayjs';
7+
import { Activity, CheckCircle, XCircle } from 'lucide-react';
8+
import React from 'react';
9+
10+
// import { useTranslation } from 'react-i18next';
11+
12+
interface ReservoirAuditLogListProps {
13+
auditLogs: ReservoirAuditLog[];
14+
loading?: boolean;
15+
filterValue?: string;
16+
onFilterChange?: (value: string) => void;
17+
pagination?: {
18+
pageSize: number;
19+
current: number;
20+
total: number;
21+
showTotal?: (total: number) => React.ReactNode;
22+
onChange?: (current: number, pageSize: number) => void;
23+
};
24+
order?: string;
25+
onChangeOrder?: (order: string) => void;
26+
}
27+
28+
const ReservoirAuditLogList: React.FC<ReservoirAuditLogListProps> = ({
29+
auditLogs,
30+
loading = false,
31+
filterValue,
32+
onFilterChange,
33+
pagination,
34+
order,
35+
onChangeOrder,
36+
}) => {
37+
// const { t } = useTranslation();
38+
39+
return (
40+
<BAIFlex direction="column" align="stretch" gap={'sm'}>
41+
<BAIFlex
42+
gap={'sm'}
43+
align="start"
44+
style={{
45+
flexShrink: 1,
46+
}}
47+
wrap="wrap"
48+
>
49+
<BAIPropertyFilter
50+
filterProperties={[
51+
{
52+
key: 'artifactName',
53+
propertyLabel: 'Artifact',
54+
type: 'string',
55+
},
56+
{
57+
key: 'operation',
58+
propertyLabel: 'Operation',
59+
type: 'string',
60+
strictSelection: true,
61+
defaultOperator: '==',
62+
options: [
63+
{ label: 'Pull', value: 'pull' },
64+
{ label: 'Install', value: 'install' },
65+
{ label: 'Uninstall', value: 'uninstall' },
66+
{ label: 'Update', value: 'update' },
67+
{ label: 'Verify', value: 'verify' },
68+
{ label: 'Delete', value: 'delete' },
69+
],
70+
},
71+
{
72+
key: 'modifier',
73+
propertyLabel: 'Modifier',
74+
type: 'string',
75+
},
76+
{
77+
key: 'status',
78+
propertyLabel: 'Status',
79+
type: 'string',
80+
strictSelection: true,
81+
defaultOperator: '==',
82+
options: [
83+
{ label: 'Success', value: 'success' },
84+
{ label: 'Failed', value: 'failed' },
85+
{ label: 'In Progress', value: 'in_progress' },
86+
],
87+
},
88+
]}
89+
value={filterValue}
90+
onChange={onFilterChange}
91+
/>
92+
</BAIFlex>
93+
<BAITable
94+
size="small"
95+
dataSource={auditLogs}
96+
rowKey="id"
97+
loading={loading}
98+
columns={[
99+
{
100+
title: 'Artifact',
101+
dataIndex: 'artifactName',
102+
key: 'artifactName',
103+
render: (artifactName: string) => (
104+
<Typography.Text strong>{artifactName}</Typography.Text>
105+
),
106+
sorter: true,
107+
},
108+
{
109+
title: 'Version',
110+
dataIndex: 'artifactVersion',
111+
key: 'artifactVersion',
112+
render: (version: string) =>
113+
version ? <BAIText monospace>{version}</BAIText> : '-',
114+
},
115+
{
116+
title: 'Operation',
117+
dataIndex: 'operation',
118+
key: 'operation',
119+
render: (operation: string) => <Tag>{operation.toUpperCase()}</Tag>,
120+
sorter: true,
121+
},
122+
{
123+
title: 'Modifier',
124+
dataIndex: 'modifier',
125+
key: 'modifier',
126+
render: (modifier: string) => (
127+
<Typography.Text>{modifier}</Typography.Text>
128+
),
129+
sorter: true,
130+
},
131+
{
132+
title: 'Timestamp',
133+
dataIndex: 'timestamp',
134+
key: 'timestamp',
135+
render: (timestamp: string) => (
136+
<Typography.Text type="secondary">
137+
{dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}
138+
</Typography.Text>
139+
),
140+
sorter: true,
141+
},
142+
]}
143+
pagination={pagination}
144+
scroll={{ x: 'max-content' }}
145+
// order={order}
146+
expandable={{
147+
expandedRowRender: (record) => (
148+
<BAIFlex direction="column" gap="xs" style={{ padding: '8px 0' }}>
149+
<BAIFlex align="center" gap="xs">
150+
<Typography.Text strong>Status:</Typography.Text>
151+
<Tag
152+
color={
153+
record.status === 'success'
154+
? 'green'
155+
: record.status === 'failed'
156+
? 'red'
157+
: 'blue'
158+
}
159+
icon={
160+
record.status === 'success' ? (
161+
<CheckCircle size={12} />
162+
) : record.status === 'failed' ? (
163+
<XCircle size={12} />
164+
) : (
165+
<Activity size={12} />
166+
)
167+
}
168+
>
169+
{record.status.toUpperCase()}
170+
</Tag>
171+
</BAIFlex>
172+
{record.details && (
173+
<BAIFlex align="start" gap="xs">
174+
<Typography.Text strong>Details:</Typography.Text>
175+
<Typography.Text type="secondary">
176+
{record.details}
177+
</Typography.Text>
178+
</BAIFlex>
179+
)}
180+
</BAIFlex>
181+
),
182+
expandRowByClick: true,
183+
}}
184+
/>
185+
</BAIFlex>
186+
);
187+
};
188+
189+
export default ReservoirAuditLogList;

0 commit comments

Comments
 (0)