balibabu commited on
Commit
17d873a
·
1 Parent(s): 116c571

feat: Bind data to TenantTable #2846 (#2883)

Browse files

### What problem does this PR solve?

feat: Bind data to TenantTable #2846
feat: Add TenantTable

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

web/src/hooks/user-setting-hooks.tsx CHANGED
@@ -2,8 +2,19 @@ import { LanguageTranslationMap } from '@/constants/common';
2
  import { ResponseGetType } from '@/interfaces/database/base';
3
  import { IToken } from '@/interfaces/database/chat';
4
  import { ITenantInfo } from '@/interfaces/database/knowledge';
5
- import { ISystemStatus, IUserInfo } from '@/interfaces/database/user-setting';
6
- import userService from '@/services/user-service';
 
 
 
 
 
 
 
 
 
 
 
7
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
8
  import { Modal, message } from 'antd';
9
  import DOMPurify from 'dompurify';
@@ -215,3 +226,125 @@ export const useCreateSystemToken = () => {
215
 
216
  return { data, loading, createToken: mutateAsync };
217
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import { ResponseGetType } from '@/interfaces/database/base';
3
  import { IToken } from '@/interfaces/database/chat';
4
  import { ITenantInfo } from '@/interfaces/database/knowledge';
5
+ import {
6
+ ISystemStatus,
7
+ ITenant,
8
+ ITenantUser,
9
+ IUserInfo,
10
+ } from '@/interfaces/database/user-setting';
11
+ import userService, {
12
+ addTenantUser,
13
+ agreeTenant,
14
+ deleteTenantUser,
15
+ listTenant,
16
+ listTenantUser,
17
+ } from '@/services/user-service';
18
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
19
  import { Modal, message } from 'antd';
20
  import DOMPurify from 'dompurify';
 
226
 
227
  return { data, loading, createToken: mutateAsync };
228
  };
229
+
230
+ export const useListTenantUser = () => {
231
+ const { data: tenantInfo } = useFetchTenantInfo();
232
+ const tenantId = tenantInfo.tenant_id;
233
+ const {
234
+ data,
235
+ isFetching: loading,
236
+ refetch,
237
+ } = useQuery<ITenantUser[]>({
238
+ queryKey: ['listTenantUser', tenantId],
239
+ initialData: [],
240
+ gcTime: 0,
241
+ enabled: !!tenantId,
242
+ queryFn: async () => {
243
+ const { data } = await listTenantUser(tenantId);
244
+
245
+ return data?.data ?? [];
246
+ },
247
+ });
248
+
249
+ return { data, loading, refetch };
250
+ };
251
+
252
+ export const useAddTenantUser = () => {
253
+ const { data: tenantInfo } = useFetchTenantInfo();
254
+ const queryClient = useQueryClient();
255
+ const {
256
+ data,
257
+ isPending: loading,
258
+ mutateAsync,
259
+ } = useMutation({
260
+ mutationKey: ['addTenantUser'],
261
+ mutationFn: async (email: string) => {
262
+ const { data } = await addTenantUser(tenantInfo.tenant_id, email);
263
+ if (data.retcode === 0) {
264
+ queryClient.invalidateQueries({ queryKey: ['listTenantUser'] });
265
+ }
266
+ return data?.retcode;
267
+ },
268
+ });
269
+
270
+ return { data, loading, addTenantUser: mutateAsync };
271
+ };
272
+
273
+ export const useDeleteTenantUser = () => {
274
+ const { data: tenantInfo } = useFetchTenantInfo();
275
+ const queryClient = useQueryClient();
276
+ const { t } = useTranslation();
277
+
278
+ const {
279
+ data,
280
+ isPending: loading,
281
+ mutateAsync,
282
+ } = useMutation({
283
+ mutationKey: ['deleteTenantUser'],
284
+ mutationFn: async ({
285
+ userId,
286
+ tenantId,
287
+ }: {
288
+ userId: string;
289
+ tenantId?: string;
290
+ }) => {
291
+ const { data } = await deleteTenantUser({
292
+ tenantId: tenantId ?? tenantInfo.tenant_id,
293
+ userId,
294
+ });
295
+ if (data.retcode === 0) {
296
+ message.success(t('message.deleted'));
297
+ queryClient.invalidateQueries({ queryKey: ['listTenantUser'] });
298
+ queryClient.invalidateQueries({ queryKey: ['listTenant'] });
299
+ }
300
+ return data?.data ?? [];
301
+ },
302
+ });
303
+
304
+ return { data, loading, deleteTenantUser: mutateAsync };
305
+ };
306
+
307
+ export const useListTenant = () => {
308
+ const { data: tenantInfo } = useFetchTenantInfo();
309
+ const tenantId = tenantInfo.tenant_id;
310
+ const {
311
+ data,
312
+ isFetching: loading,
313
+ refetch,
314
+ } = useQuery<ITenant[]>({
315
+ queryKey: ['listTenant', tenantId],
316
+ initialData: [],
317
+ gcTime: 0,
318
+ enabled: !!tenantId,
319
+ queryFn: async () => {
320
+ const { data } = await listTenant();
321
+
322
+ return data?.data ?? [];
323
+ },
324
+ });
325
+
326
+ return { data, loading, refetch };
327
+ };
328
+
329
+ export const useAgreeTenant = () => {
330
+ const queryClient = useQueryClient();
331
+ const { t } = useTranslation();
332
+
333
+ const {
334
+ data,
335
+ isPending: loading,
336
+ mutateAsync,
337
+ } = useMutation({
338
+ mutationKey: ['agreeTenant'],
339
+ mutationFn: async (tenantId: string) => {
340
+ const { data } = await agreeTenant(tenantId);
341
+ if (data.retcode === 0) {
342
+ message.success(t('message.operated'));
343
+ queryClient.invalidateQueries({ queryKey: ['listTenant'] });
344
+ }
345
+ return data?.data ?? [];
346
+ },
347
+ });
348
+
349
+ return { data, loading, agreeTenant: mutateAsync };
350
+ };
web/src/interfaces/database/user-setting.ts CHANGED
@@ -60,3 +60,28 @@ interface Es {
60
  number_of_nodes: number;
61
  active_shards: number;
62
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  number_of_nodes: number;
61
  active_shards: number;
62
  }
63
+
64
+ export interface ITenantUser {
65
+ avatar: null;
66
+ delta_seconds: number;
67
+ email: string;
68
+ is_active: string;
69
+ is_anonymous: string;
70
+ is_authenticated: string;
71
+ is_superuser: boolean;
72
+ nickname: string;
73
+ role: string;
74
+ status: string;
75
+ update_date: string;
76
+ user_id: string;
77
+ }
78
+
79
+ export interface ITenant {
80
+ avatar: string;
81
+ delta_seconds: number;
82
+ email: string;
83
+ nickname: string;
84
+ role: string;
85
+ tenant_id: string;
86
+ update_date: string;
87
+ }
web/src/locales/en.ts CHANGED
@@ -27,7 +27,8 @@ export default {
27
  close: 'Close',
28
  preview: 'Preview',
29
  move: 'Move',
30
- warn: '提醒',
 
31
  },
32
  login: {
33
  login: 'Sign in',
@@ -584,6 +585,14 @@ The above is the content you need to summarize.`,
584
  'Please add both embedding model and LLM in <b>Settings > Model providers</b> firstly.',
585
  apiVersion: 'API-Version',
586
  apiVersionMessage: 'Please input API version',
 
 
 
 
 
 
 
 
587
  },
588
  message: {
589
  registered: 'Registered!',
 
27
  close: 'Close',
28
  preview: 'Preview',
29
  move: 'Move',
30
+ warn: 'Warn',
31
+ action: 'Action',
32
  },
33
  login: {
34
  login: 'Sign in',
 
585
  'Please add both embedding model and LLM in <b>Settings > Model providers</b> firstly.',
586
  apiVersion: 'API-Version',
587
  apiVersionMessage: 'Please input API version',
588
+ add: 'Add',
589
+ updateDate: 'Update Date',
590
+ role: 'Role',
591
+ invite: 'Invite',
592
+ agree: 'Agree',
593
+ refuse: 'Refuse',
594
+ teamMembers: 'Team Members',
595
+ joinedTeams: 'Joined Teams',
596
  },
597
  message: {
598
  registered: 'Registered!',
web/src/locales/zh-traditional.ts CHANGED
@@ -28,6 +28,7 @@ export default {
28
  preview: '預覽',
29
  move: '移動',
30
  warn: '提醒',
 
31
  },
32
  login: {
33
  login: '登入',
@@ -540,6 +541,14 @@ export default {
540
  GoogleRegionMessage: '請輸入 Google Cloud 區域',
541
  modelProvidersWarn:
542
  '請先在 <b>「設定」>「模型提供者」</b> 中新增嵌入模型和LLM。',
 
 
 
 
 
 
 
 
543
  },
544
  message: {
545
  registered: '註冊成功',
 
28
  preview: '預覽',
29
  move: '移動',
30
  warn: '提醒',
31
+ action: '操作',
32
  },
33
  login: {
34
  login: '登入',
 
541
  GoogleRegionMessage: '請輸入 Google Cloud 區域',
542
  modelProvidersWarn:
543
  '請先在 <b>「設定」>「模型提供者」</b> 中新增嵌入模型和LLM。',
544
+ add: '添加',
545
+ updateDate: '更新日期',
546
+ role: '角色',
547
+ invite: '邀請',
548
+ agree: '同意',
549
+ refuse: '拒絕',
550
+ teamMembers: '團隊成員',
551
+ joinedTeams: '加入的團隊',
552
  },
553
  message: {
554
  registered: '註冊成功',
web/src/locales/zh.ts CHANGED
@@ -28,6 +28,7 @@ export default {
28
  preview: '预览',
29
  move: '移动',
30
  warn: '提醒',
 
31
  },
32
  login: {
33
  login: '登录',
@@ -559,6 +560,14 @@ export default {
559
  '请首先在 <b>设置 > 模型提供商</b> 中添加嵌入模型和 LLM。',
560
  apiVersion: 'API版本',
561
  apiVersionMessage: '请输入API版本!',
 
 
 
 
 
 
 
 
562
  },
563
  message: {
564
  registered: '注册成功',
 
28
  preview: '预览',
29
  move: '移动',
30
  warn: '提醒',
31
+ action: '操作',
32
  },
33
  login: {
34
  login: '登录',
 
560
  '请首先在 <b>设置 > 模型提供商</b> 中添加嵌入模型和 LLM。',
561
  apiVersion: 'API版本',
562
  apiVersionMessage: '请输入API版本!',
563
+ add: '添加',
564
+ updateDate: '更新日期',
565
+ role: '角色',
566
+ invite: '邀请',
567
+ agree: '同意',
568
+ refuse: '拒绝',
569
+ teamMembers: '团队成员',
570
+ joinedTeams: '加入的团队',
571
  },
572
  message: {
573
  registered: '注册成功',
web/src/pages/user-setting/constants.tsx CHANGED
@@ -30,3 +30,9 @@ export const LocalLlmFactories = [
30
  'OpenRouter',
31
  'HuggingFace',
32
  ];
 
 
 
 
 
 
 
30
  'OpenRouter',
31
  'HuggingFace',
32
  ];
33
+
34
+ export enum TenantRole {
35
+ Owner = 'owner',
36
+ Invite = 'invite',
37
+ Normal = 'normal',
38
+ }
web/src/pages/user-setting/setting-team/add-user-modal.tsx ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { IModalProps } from '@/interfaces/common';
2
+ import { Form, Input, Modal } from 'antd';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ const AddingUserModal = ({
6
+ visible,
7
+ hideModal,
8
+ loading,
9
+ onOk,
10
+ }: IModalProps<string>) => {
11
+ const [form] = Form.useForm();
12
+ const { t } = useTranslation();
13
+
14
+ type FieldType = {
15
+ email?: string;
16
+ };
17
+
18
+ const handleOk = async () => {
19
+ const ret = await form.validateFields();
20
+
21
+ return onOk?.(ret.email);
22
+ };
23
+
24
+ return (
25
+ <Modal
26
+ title={t('setting.add')}
27
+ open={visible}
28
+ onOk={handleOk}
29
+ onCancel={hideModal}
30
+ okButtonProps={{ loading }}
31
+ confirmLoading={loading}
32
+ >
33
+ <Form
34
+ name="basic"
35
+ labelCol={{ span: 6 }}
36
+ wrapperCol={{ span: 18 }}
37
+ autoComplete="off"
38
+ form={form}
39
+ >
40
+ <Form.Item<FieldType>
41
+ label={t('setting.email')}
42
+ name="email"
43
+ rules={[{ required: true, message: t('namePlaceholder') }]}
44
+ >
45
+ <Input />
46
+ </Form.Item>
47
+ </Form>
48
+ </Modal>
49
+ );
50
+ };
51
+
52
+ export default AddingUserModal;
web/src/pages/user-setting/setting-team/hooks.ts ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
2
+ import {
3
+ useAddTenantUser,
4
+ useAgreeTenant,
5
+ useDeleteTenantUser,
6
+ useFetchUserInfo,
7
+ } from '@/hooks/user-setting-hooks';
8
+ import { useCallback } from 'react';
9
+
10
+ export const useAddUser = () => {
11
+ const { addTenantUser } = useAddTenantUser();
12
+ const {
13
+ visible: addingTenantModalVisible,
14
+ hideModal: hideAddingTenantModal,
15
+ showModal: showAddingTenantModal,
16
+ } = useSetModalState();
17
+
18
+ const handleAddUserOk = useCallback(
19
+ async (email: string) => {
20
+ const retcode = await addTenantUser(email);
21
+ if (retcode === 0) {
22
+ hideAddingTenantModal();
23
+ }
24
+ },
25
+ [addTenantUser, hideAddingTenantModal],
26
+ );
27
+
28
+ return {
29
+ addingTenantModalVisible,
30
+ hideAddingTenantModal,
31
+ showAddingTenantModal,
32
+ handleAddUserOk,
33
+ };
34
+ };
35
+
36
+ export const useHandleDeleteUser = () => {
37
+ const { deleteTenantUser, loading } = useDeleteTenantUser();
38
+ const showDeleteConfirm = useShowDeleteConfirm();
39
+
40
+ const handleDeleteTenantUser = (userId: string) => () => {
41
+ showDeleteConfirm({
42
+ onOk: async () => {
43
+ const retcode = await deleteTenantUser({ userId });
44
+ if (retcode === 0) {
45
+ }
46
+ return;
47
+ },
48
+ });
49
+ };
50
+
51
+ return { handleDeleteTenantUser, loading };
52
+ };
53
+
54
+ export const useHandleAgreeTenant = () => {
55
+ const { agreeTenant } = useAgreeTenant();
56
+ const { deleteTenantUser } = useDeleteTenantUser();
57
+ const { data: user } = useFetchUserInfo();
58
+
59
+ const handleAgree = (tenantId: string, isAgree: boolean) => () => {
60
+ if (isAgree) {
61
+ agreeTenant(tenantId);
62
+ } else {
63
+ deleteTenantUser({ tenantId, userId: user.id });
64
+ }
65
+ };
66
+
67
+ return { handleAgree };
68
+ };
web/src/pages/user-setting/setting-team/index.less CHANGED
@@ -1,5 +1,8 @@
1
  .teamWrapper {
2
  width: 100%;
 
 
 
3
  .teamCard {
4
  // width: 100%;
5
  }
 
1
  .teamWrapper {
2
  width: 100%;
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 20px;
6
  .teamCard {
7
  // width: 100%;
8
  }
web/src/pages/user-setting/setting-team/index.tsx CHANGED
@@ -1,25 +1,70 @@
1
- import { Button, Card, Flex } from 'antd';
 
 
 
 
 
2
 
3
- import { useTranslate } from '@/hooks/common-hooks';
4
- import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
 
5
  import styles from './index.less';
 
 
 
 
6
 
7
  const UserSettingTeam = () => {
8
  const { data: userInfo } = useFetchUserInfo();
9
- const { t } = useTranslate('setting');
 
 
 
 
 
 
 
10
 
11
  return (
12
  <div className={styles.teamWrapper}>
13
  <Card className={styles.teamCard}>
14
  <Flex align="center" justify={'space-between'}>
15
  <span>
16
- {userInfo.nickname} {t('workspace')}
17
  </span>
18
- <Button type="primary" disabled>
19
- {t('upgrade')}
 
20
  </Button>
21
  </Flex>
22
  </Card>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  </div>
24
  );
25
  };
 
1
+ import {
2
+ useFetchUserInfo,
3
+ useListTenantUser,
4
+ } from '@/hooks/user-setting-hooks';
5
+ import { Button, Card, Flex, Space } from 'antd';
6
+ import { useTranslation } from 'react-i18next';
7
 
8
+ import { TeamOutlined, UserAddOutlined, UserOutlined } from '@ant-design/icons';
9
+ import AddingUserModal from './add-user-modal';
10
+ import { useAddUser } from './hooks';
11
  import styles from './index.less';
12
+ import TenantTable from './tenant-table';
13
+ import UserTable from './user-table';
14
+
15
+ const iconStyle = { fontSize: 20, color: '#1677ff' };
16
 
17
  const UserSettingTeam = () => {
18
  const { data: userInfo } = useFetchUserInfo();
19
+ const { t } = useTranslation();
20
+ useListTenantUser();
21
+ const {
22
+ addingTenantModalVisible,
23
+ hideAddingTenantModal,
24
+ showAddingTenantModal,
25
+ handleAddUserOk,
26
+ } = useAddUser();
27
 
28
  return (
29
  <div className={styles.teamWrapper}>
30
  <Card className={styles.teamCard}>
31
  <Flex align="center" justify={'space-between'}>
32
  <span>
33
+ {userInfo.nickname} {t('setting.workspace')}
34
  </span>
35
+ <Button type="primary" onClick={showAddingTenantModal}>
36
+ <UserAddOutlined />
37
+ {t('setting.invite')}
38
  </Button>
39
  </Flex>
40
  </Card>
41
+ <Card
42
+ title={
43
+ <Space>
44
+ <UserOutlined style={iconStyle} /> {t('setting.teamMembers')}
45
+ </Space>
46
+ }
47
+ bordered={false}
48
+ >
49
+ <UserTable></UserTable>
50
+ </Card>
51
+ <Card
52
+ title={
53
+ <Space>
54
+ <TeamOutlined style={iconStyle} /> {t('setting.joinedTeams')}
55
+ </Space>
56
+ }
57
+ bordered={false}
58
+ >
59
+ <TenantTable></TenantTable>
60
+ </Card>
61
+ {addingTenantModalVisible && (
62
+ <AddingUserModal
63
+ visible
64
+ hideModal={hideAddingTenantModal}
65
+ onOk={handleAddUserOk}
66
+ ></AddingUserModal>
67
+ )}
68
  </div>
69
  );
70
  };
web/src/pages/user-setting/setting-team/tenant-table.tsx ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useListTenant } from '@/hooks/user-setting-hooks';
2
+ import { ITenant } from '@/interfaces/database/user-setting';
3
+ import { formatDate } from '@/utils/date';
4
+ import type { TableProps } from 'antd';
5
+ import { Button, Space, Table } from 'antd';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { TenantRole } from '../constants';
8
+ import { useHandleAgreeTenant } from './hooks';
9
+
10
+ const TenantTable = () => {
11
+ const { t } = useTranslation();
12
+ const { data, loading } = useListTenant();
13
+ const { handleAgree } = useHandleAgreeTenant();
14
+
15
+ const columns: TableProps<ITenant>['columns'] = [
16
+ {
17
+ title: t('common.name'),
18
+ dataIndex: 'nickname',
19
+ key: 'nickname',
20
+ },
21
+ {
22
+ title: t('setting.email'),
23
+ dataIndex: 'email',
24
+ key: 'email',
25
+ },
26
+ {
27
+ title: t('setting.updateDate'),
28
+ dataIndex: 'update_date',
29
+ key: 'update_date',
30
+ render(value) {
31
+ return formatDate(value);
32
+ },
33
+ },
34
+ {
35
+ title: t('common.action'),
36
+ key: 'action',
37
+ render: (_, { role, tenant_id }) => {
38
+ if (role === TenantRole.Invite) {
39
+ return (
40
+ <Space>
41
+ <Button type="link" onClick={handleAgree(tenant_id, true)}>
42
+ {t(`setting.agree`)}
43
+ </Button>
44
+ <Button type="link" onClick={handleAgree(tenant_id, false)}>
45
+ {t(`setting.refuse`)}
46
+ </Button>
47
+ </Space>
48
+ );
49
+ }
50
+ },
51
+ },
52
+ ];
53
+
54
+ return (
55
+ <Table<ITenant>
56
+ columns={columns}
57
+ dataSource={data}
58
+ rowKey={'tenant_id'}
59
+ loading={loading}
60
+ pagination={false}
61
+ />
62
+ );
63
+ };
64
+
65
+ export default TenantTable;
web/src/pages/user-setting/setting-team/user-table.tsx ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useListTenantUser } from '@/hooks/user-setting-hooks';
2
+ import { ITenantUser } from '@/interfaces/database/user-setting';
3
+ import { formatDate } from '@/utils/date';
4
+ import { DeleteOutlined } from '@ant-design/icons';
5
+ import type { TableProps } from 'antd';
6
+ import { Button, Table, Tag } from 'antd';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { TenantRole } from '../constants';
9
+ import { useHandleDeleteUser } from './hooks';
10
+
11
+ const ColorMap = {
12
+ [TenantRole.Normal]: 'green',
13
+ [TenantRole.Invite]: 'orange',
14
+ [TenantRole.Owner]: 'red',
15
+ };
16
+
17
+ const UserTable = () => {
18
+ const { data, loading } = useListTenantUser();
19
+ const { handleDeleteTenantUser } = useHandleDeleteUser();
20
+ const { t } = useTranslation();
21
+
22
+ const columns: TableProps<ITenantUser>['columns'] = [
23
+ {
24
+ title: t('common.name'),
25
+ dataIndex: 'nickname',
26
+ key: 'nickname',
27
+ },
28
+ {
29
+ title: t('setting.email'),
30
+ dataIndex: 'email',
31
+ key: 'email',
32
+ },
33
+ {
34
+ title: t('setting.role'),
35
+ dataIndex: 'role',
36
+ key: 'role',
37
+ render(value, { role }) {
38
+ return (
39
+ <Tag color={ColorMap[role as keyof typeof ColorMap]}>{role}</Tag>
40
+ );
41
+ },
42
+ },
43
+ {
44
+ title: t('setting.updateDate'),
45
+ dataIndex: 'update_date',
46
+ key: 'update_date',
47
+ render(value) {
48
+ return formatDate(value);
49
+ },
50
+ },
51
+ {
52
+ title: t('common.action'),
53
+ key: 'action',
54
+ render: (_, record) => (
55
+ <Button type="text" onClick={handleDeleteTenantUser(record.user_id)}>
56
+ <DeleteOutlined size={20} />
57
+ </Button>
58
+ ),
59
+ },
60
+ ];
61
+
62
+ return (
63
+ <Table<ITenantUser>
64
+ rowKey={'user_id'}
65
+ columns={columns}
66
+ dataSource={data}
67
+ loading={loading}
68
+ pagination={false}
69
+ />
70
+ );
71
+ };
72
+
73
+ export default UserTable;
web/src/services/user-service.ts CHANGED
@@ -1,6 +1,6 @@
1
  import api from '@/utils/api';
2
  import registerServer from '@/utils/register-server';
3
- import request from '@/utils/request';
4
 
5
  const {
6
  login,
@@ -105,4 +105,23 @@ const methods = {
105
 
106
  const userService = registerServer<keyof typeof methods>(methods, request);
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  export default userService;
 
1
  import api from '@/utils/api';
2
  import registerServer from '@/utils/register-server';
3
+ import request, { post } from '@/utils/request';
4
 
5
  const {
6
  login,
 
105
 
106
  const userService = registerServer<keyof typeof methods>(methods, request);
107
 
108
+ export const listTenantUser = (tenantId: string) =>
109
+ request.get(api.listTenantUser(tenantId));
110
+
111
+ export const addTenantUser = (tenantId: string, email: string) =>
112
+ post(api.addTenantUser(tenantId), { email });
113
+
114
+ export const deleteTenantUser = ({
115
+ tenantId,
116
+ userId,
117
+ }: {
118
+ tenantId: string;
119
+ userId: string;
120
+ }) => request.delete(api.deleteTenantUser(tenantId, userId));
121
+
122
+ export const listTenant = () => request.get(api.listTenant);
123
+
124
+ export const agreeTenant = (tenantId: string) =>
125
+ request.put(api.agreeTenant(tenantId));
126
+
127
  export default userService;
web/src/utils/api.ts CHANGED
@@ -12,6 +12,15 @@ export default {
12
  tenant_info: `${api_host}/user/tenant_info`,
13
  set_tenant_info: `${api_host}/user/set_tenant_info`,
14
 
 
 
 
 
 
 
 
 
 
15
  // llm model
16
  factories_list: `${api_host}/llm/factories`,
17
  llm_list: `${api_host}/llm/list`,
 
12
  tenant_info: `${api_host}/user/tenant_info`,
13
  set_tenant_info: `${api_host}/user/set_tenant_info`,
14
 
15
+ // team
16
+ addTenantUser: (tenantId: string) => `${api_host}/tenant/${tenantId}/user`,
17
+ listTenantUser: (tenantId: string) =>
18
+ `${api_host}/tenant/${tenantId}/user/list`,
19
+ deleteTenantUser: (tenantId: string, userId: string) =>
20
+ `${api_host}/tenant/${tenantId}/user/${userId}`,
21
+ listTenant: `${api_host}/tenant/list`,
22
+ agreeTenant: (tenantId: string) => `${api_host}/tenant/agree/${tenantId}`,
23
+
24
  // llm model
25
  factories_list: `${api_host}/llm/factories`,
26
  llm_list: `${api_host}/llm/list`,
web/src/utils/request.ts CHANGED
@@ -135,3 +135,15 @@ request.interceptors.response.use(async (response: any, options) => {
135
  });
136
 
137
  export default request;
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  });
136
 
137
  export default request;
138
+
139
+ export const get = (url: string) => {
140
+ return request.get(url);
141
+ };
142
+
143
+ export const post = (url: string, body: any) => {
144
+ return request.post(url, { data: body });
145
+ };
146
+
147
+ export const drop = () => {};
148
+
149
+ export const put = () => {};