Skip to content

Commit e0d7442

Browse files
authored
feat: Bind data to TenantTable infiniflow#2846 (infiniflow#2883)
### What problem does this PR solve? feat: Bind data to TenantTable infiniflow#2846 feat: Add TenantTable ### Type of change - [x] New Feature (non-breaking change which adds functionality)
1 parent cf8bab8 commit e0d7442

File tree

15 files changed

+548
-11
lines changed

15 files changed

+548
-11
lines changed

web/src/hooks/user-setting-hooks.tsx

+135-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,19 @@ import { LanguageTranslationMap } from '@/constants/common';
22
import { ResponseGetType } from '@/interfaces/database/base';
33
import { IToken } from '@/interfaces/database/chat';
44
import { ITenantInfo } from '@/interfaces/database/knowledge';
5-
import { ISystemStatus, IUserInfo } from '@/interfaces/database/user-setting';
6-
import userService from '@/services/user-service';
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';
718
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
819
import { Modal, message } from 'antd';
920
import DOMPurify from 'dompurify';
@@ -215,3 +226,125 @@ export const useCreateSystemToken = () => {
215226

216227
return { data, loading, createToken: mutateAsync };
217228
};
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

+25
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,28 @@ interface Es {
6060
number_of_nodes: number;
6161
active_shards: number;
6262
}
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

+10-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export default {
2727
close: 'Close',
2828
preview: 'Preview',
2929
move: 'Move',
30-
warn: '提醒',
30+
warn: 'Warn',
31+
action: 'Action',
3132
},
3233
login: {
3334
login: 'Sign in',
@@ -584,6 +585,14 @@ The above is the content you need to summarize.`,
584585
'Please add both embedding model and LLM in <b>Settings > Model providers</b> firstly.',
585586
apiVersion: 'API-Version',
586587
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',
587596
},
588597
message: {
589598
registered: 'Registered!',

web/src/locales/zh-traditional.ts

+9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default {
2828
preview: '預覽',
2929
move: '移動',
3030
warn: '提醒',
31+
action: '操作',
3132
},
3233
login: {
3334
login: '登入',
@@ -540,6 +541,14 @@ export default {
540541
GoogleRegionMessage: '請輸入 Google Cloud 區域',
541542
modelProvidersWarn:
542543
'請先在 <b>「設定」>「模型提供者」</b> 中新增嵌入模型和LLM。',
544+
add: '添加',
545+
updateDate: '更新日期',
546+
role: '角色',
547+
invite: '邀請',
548+
agree: '同意',
549+
refuse: '拒絕',
550+
teamMembers: '團隊成員',
551+
joinedTeams: '加入的團隊',
543552
},
544553
message: {
545554
registered: '註冊成功',

web/src/locales/zh.ts

+9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default {
2828
preview: '预览',
2929
move: '移动',
3030
warn: '提醒',
31+
action: '操作',
3132
},
3233
login: {
3334
login: '登录',
@@ -559,6 +560,14 @@ export default {
559560
'请首先在 <b>设置 > 模型提供商</b> 中添加嵌入模型和 LLM。',
560561
apiVersion: 'API版本',
561562
apiVersionMessage: '请输入API版本!',
563+
add: '添加',
564+
updateDate: '更新日期',
565+
role: '角色',
566+
invite: '邀请',
567+
agree: '同意',
568+
refuse: '拒绝',
569+
teamMembers: '团队成员',
570+
joinedTeams: '加入的团队',
562571
},
563572
message: {
564573
registered: '注册成功',

web/src/pages/user-setting/constants.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,9 @@ export const LocalLlmFactories = [
3030
'OpenRouter',
3131
'HuggingFace',
3232
];
33+
34+
export enum TenantRole {
35+
Owner = 'owner',
36+
Invite = 'invite',
37+
Normal = 'normal',
38+
}
Original file line numberDiff line numberDiff line change
@@ -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;
Original file line numberDiff line numberDiff line change
@@ -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

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
.teamWrapper {
22
width: 100%;
3+
display: flex;
4+
flex-direction: column;
5+
gap: 20px;
36
.teamCard {
47
// width: 100%;
58
}

0 commit comments

Comments
 (0)