From c37bda46361f743c1c5a7a280a1d4bde04c42e5b Mon Sep 17 00:00:00 2001 From: SungChul Hong Date: Tue, 17 Dec 2024 13:06:55 +0900 Subject: [PATCH] feat: export users and credential to csv --- react/src/components/UserCredentialList.tsx | 587 +++++++++++--------- react/src/components/UserNodeList.tsx | 318 ++++++----- resources/i18n/de.json | 4 +- resources/i18n/el.json | 4 +- resources/i18n/en.json | 4 +- resources/i18n/es.json | 4 +- resources/i18n/fi.json | 2 + resources/i18n/fr.json | 4 +- resources/i18n/id.json | 2 + resources/i18n/it.json | 4 +- resources/i18n/ja.json | 2 + resources/i18n/ko.json | 2 + resources/i18n/mn.json | 2 + resources/i18n/ms.json | 2 + resources/i18n/pl.json | 2 + resources/i18n/pt-BR.json | 2 + resources/i18n/pt.json | 2 + resources/i18n/ru.json | 4 +- resources/i18n/th.json | 2 + resources/i18n/tr.json | 4 +- resources/i18n/vi.json | 2 + resources/i18n/zh-CN.json | 4 +- resources/i18n/zh-TW.json | 4 +- 23 files changed, 553 insertions(+), 414 deletions(-) diff --git a/react/src/components/UserCredentialList.tsx b/react/src/components/UserCredentialList.tsx index 84e302582..c1ed52526 100644 --- a/react/src/components/UserCredentialList.tsx +++ b/react/src/components/UserCredentialList.tsx @@ -3,6 +3,7 @@ import { filterNonNullItems, transformSorterToOrderString, } from '../helper'; +import { exportCSVWithFormattingRules } from '../helper/csv-util'; import { useUpdatableState } from '../hooks'; import { useBAIPaginationOptionState } from '../hooks/reactPaginationQueryOptions'; import BAIPropertyFilter from './BAIPropertyFilter'; @@ -21,14 +22,17 @@ import { DeleteOutlined, InfoCircleOutlined, LoadingOutlined, + MoreOutlined, ReloadOutlined, SettingOutlined, } from '@ant-design/icons'; import { App, Button, + Dropdown, Popconfirm, Radio, + TableColumnsType, Tag, Tooltip, Typography, @@ -150,6 +154,298 @@ const UserCredentialList: React.FC = () => { } `); + const columns: TableColumnsType = filterEmptyItem([ + { + key: 'user_id', + title: t('credential.UserID'), + dataIndex: 'email', + fixed: 'left', + sorter: true, + // TODO: user_id field in keypair_list is used as user's email, but sorting is done by email field + render: (value, record) => { + return record.user_id; + }, + }, + { + key: 'access_key', + title: t('credential.AccessKey'), + dataIndex: 'access_key', + sorter: true, + }, + { + key: 'is_admin', + title: t('credential.Permission'), + dataIndex: 'is_admin', + render: (isAdmin) => + isAdmin ? ( + <> + admin + user + + ) : ( + user + ), + sorter: true, + }, + { + key: 'key_age', + title: t('credential.KeyAge'), + dataIndex: 'created_at', + render: (createdAt) => { + return `${dayjs().diff(createdAt, 'day')}${t('credential.Days')}`; + }, + sorter: true, + }, + { + key: 'created_at', + title: t('credential.CreatedAt'), + dataIndex: 'created_at', + render: (createdAt) => dayjs(createdAt).format('lll'), + sorter: true, + }, + { + key: 'resource_policy', + title: t('credential.ResourcePolicy'), + dataIndex: 'resource_policy', + sorter: true, + }, + { + key: 'allocation', + title: t('credential.Allocation'), + render: (value, record) => { + return ( + + + {record.concurrency_used} + + {t('credential.Sessions')} + + + + {record.rate_limit} + + {t('credential.ReqPer15Min')} + + + + {record.num_queries} + + {t('credential.Queries')} + + + + ); + }, + }, + { + key: 'control', + title: t('general.Control'), + fixed: 'right', + render: (value, record) => { + return ( + +