Spaces:
Build error
Build error
| /* | |
| Copyright (C) 2025 QuantumNous | |
| This program is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU Affero General Public License as | |
| published by the Free Software Foundation, either version 3 of the | |
| License, or (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU Affero General Public License for more details. | |
| You should have received a copy of the GNU Affero General Public License | |
| along with this program. If not, see <https://www.gnu.org/licenses/>. | |
| For commercial licensing, please contact support@quantumnous.com | |
| */ | |
| import { useState, useEffect } from 'react'; | |
| import { useTranslation } from 'react-i18next'; | |
| import { API, showError, showSuccess } from '../../helpers'; | |
| import { ITEMS_PER_PAGE } from '../../constants'; | |
| import { useTableCompactMode } from '../common/useTableCompactMode'; | |
| export const useUsersData = () => { | |
| const { t } = useTranslation(); | |
| const [compactMode, setCompactMode] = useTableCompactMode('users'); | |
| // State management | |
| const [users, setUsers] = useState([]); | |
| const [loading, setLoading] = useState(true); | |
| const [activePage, setActivePage] = useState(1); | |
| const [pageSize, setPageSize] = useState(ITEMS_PER_PAGE); | |
| const [searching, setSearching] = useState(false); | |
| const [groupOptions, setGroupOptions] = useState([]); | |
| const [userCount, setUserCount] = useState(0); | |
| // Modal states | |
| const [showAddUser, setShowAddUser] = useState(false); | |
| const [showEditUser, setShowEditUser] = useState(false); | |
| const [editingUser, setEditingUser] = useState({ | |
| id: undefined, | |
| }); | |
| // Form initial values | |
| const formInitValues = { | |
| searchKeyword: '', | |
| searchGroup: '', | |
| }; | |
| // Form API reference | |
| const [formApi, setFormApi] = useState(null); | |
| // Get form values helper function | |
| const getFormValues = () => { | |
| const formValues = formApi ? formApi.getValues() : {}; | |
| return { | |
| searchKeyword: formValues.searchKeyword || '', | |
| searchGroup: formValues.searchGroup || '', | |
| }; | |
| }; | |
| // Set user format with key field | |
| const setUserFormat = (users) => { | |
| for (let i = 0; i < users.length; i++) { | |
| users[i].key = users[i].id; | |
| } | |
| setUsers(users); | |
| }; | |
| // Load users data | |
| const loadUsers = async (startIdx, pageSize) => { | |
| setLoading(true); | |
| const res = await API.get(`/api/user/?p=${startIdx}&page_size=${pageSize}`); | |
| const { success, message, data } = res.data; | |
| if (success) { | |
| const newPageData = data.items; | |
| setActivePage(data.page); | |
| setUserCount(data.total); | |
| setUserFormat(newPageData); | |
| } else { | |
| showError(message); | |
| } | |
| setLoading(false); | |
| }; | |
| // Search users with keyword and group | |
| const searchUsers = async ( | |
| startIdx, | |
| pageSize, | |
| searchKeyword = null, | |
| searchGroup = null, | |
| ) => { | |
| // If no parameters passed, get values from form | |
| if (searchKeyword === null || searchGroup === null) { | |
| const formValues = getFormValues(); | |
| searchKeyword = formValues.searchKeyword; | |
| searchGroup = formValues.searchGroup; | |
| } | |
| if (searchKeyword === '' && searchGroup === '') { | |
| // If keyword is blank, load files instead | |
| await loadUsers(startIdx, pageSize); | |
| return; | |
| } | |
| setSearching(true); | |
| const res = await API.get( | |
| `/api/user/search?keyword=${searchKeyword}&group=${searchGroup}&p=${startIdx}&page_size=${pageSize}`, | |
| ); | |
| const { success, message, data } = res.data; | |
| if (success) { | |
| const newPageData = data.items; | |
| setActivePage(data.page); | |
| setUserCount(data.total); | |
| setUserFormat(newPageData); | |
| } else { | |
| showError(message); | |
| } | |
| setSearching(false); | |
| }; | |
| // Manage user operations (promote, demote, enable, disable, delete) | |
| const manageUser = async (userId, action, record) => { | |
| // Trigger loading state to force table re-render | |
| setLoading(true); | |
| const res = await API.post('/api/user/manage', { | |
| id: userId, | |
| action, | |
| }); | |
| const { success, message } = res.data; | |
| if (success) { | |
| showSuccess('操作成功完成!'); | |
| const user = res.data.data; | |
| // Create a new array and new object to ensure React detects changes | |
| const newUsers = users.map((u) => { | |
| if (u.id === userId) { | |
| if (action === 'delete') { | |
| return { ...u, DeletedAt: new Date() }; | |
| } | |
| return { ...u, status: user.status, role: user.role }; | |
| } | |
| return u; | |
| }); | |
| setUsers(newUsers); | |
| } else { | |
| showError(message); | |
| } | |
| setLoading(false); | |
| }; | |
| const resetUserPasskey = async (user) => { | |
| if (!user) { | |
| return; | |
| } | |
| try { | |
| const res = await API.delete(`/api/user/${user.id}/reset_passkey`); | |
| const { success, message } = res.data; | |
| if (success) { | |
| showSuccess(t('Passkey 已重置')); | |
| } else { | |
| showError(message || t('操作失败,请重试')); | |
| } | |
| } catch (error) { | |
| showError(t('操作失败,请重试')); | |
| } | |
| }; | |
| const resetUserTwoFA = async (user) => { | |
| if (!user) { | |
| return; | |
| } | |
| try { | |
| const res = await API.delete(`/api/user/${user.id}/2fa`); | |
| const { success, message } = res.data; | |
| if (success) { | |
| showSuccess(t('二步验证已重置')); | |
| } else { | |
| showError(message || t('操作失败,请重试')); | |
| } | |
| } catch (error) { | |
| showError(t('操作失败,请重试')); | |
| } | |
| }; | |
| // Handle page change | |
| const handlePageChange = (page) => { | |
| setActivePage(page); | |
| const { searchKeyword, searchGroup } = getFormValues(); | |
| if (searchKeyword === '' && searchGroup === '') { | |
| loadUsers(page, pageSize).then(); | |
| } else { | |
| searchUsers(page, pageSize, searchKeyword, searchGroup).then(); | |
| } | |
| }; | |
| // Handle page size change | |
| const handlePageSizeChange = async (size) => { | |
| localStorage.setItem('page-size', size + ''); | |
| setPageSize(size); | |
| setActivePage(1); | |
| loadUsers(activePage, size) | |
| .then() | |
| .catch((reason) => { | |
| showError(reason); | |
| }); | |
| }; | |
| // Handle table row styling for disabled/deleted users | |
| const handleRow = (record, index) => { | |
| if (record.DeletedAt !== null || record.status !== 1) { | |
| return { | |
| style: { | |
| background: 'var(--semi-color-disabled-border)', | |
| }, | |
| }; | |
| } else { | |
| return {}; | |
| } | |
| }; | |
| // Refresh data | |
| const refresh = async (page = activePage) => { | |
| const { searchKeyword, searchGroup } = getFormValues(); | |
| if (searchKeyword === '' && searchGroup === '') { | |
| await loadUsers(page, pageSize); | |
| } else { | |
| await searchUsers(page, pageSize, searchKeyword, searchGroup); | |
| } | |
| }; | |
| // Fetch groups data | |
| const fetchGroups = async () => { | |
| try { | |
| let res = await API.get(`/api/group/`); | |
| if (res === undefined) { | |
| return; | |
| } | |
| setGroupOptions( | |
| res.data.data.map((group) => ({ | |
| label: group, | |
| value: group, | |
| })), | |
| ); | |
| } catch (error) { | |
| showError(error.message); | |
| } | |
| }; | |
| // Modal control functions | |
| const closeAddUser = () => { | |
| setShowAddUser(false); | |
| }; | |
| const closeEditUser = () => { | |
| setShowEditUser(false); | |
| setEditingUser({ | |
| id: undefined, | |
| }); | |
| }; | |
| // Initialize data on component mount | |
| useEffect(() => { | |
| loadUsers(0, pageSize) | |
| .then() | |
| .catch((reason) => { | |
| showError(reason); | |
| }); | |
| fetchGroups().then(); | |
| }, []); | |
| return { | |
| // Data state | |
| users, | |
| loading, | |
| activePage, | |
| pageSize, | |
| userCount, | |
| searching, | |
| groupOptions, | |
| // Modal state | |
| showAddUser, | |
| showEditUser, | |
| editingUser, | |
| setShowAddUser, | |
| setShowEditUser, | |
| setEditingUser, | |
| // Form state | |
| formInitValues, | |
| formApi, | |
| setFormApi, | |
| // UI state | |
| compactMode, | |
| setCompactMode, | |
| // Actions | |
| loadUsers, | |
| searchUsers, | |
| manageUser, | |
| resetUserPasskey, | |
| resetUserTwoFA, | |
| handlePageChange, | |
| handlePageSizeChange, | |
| handleRow, | |
| refresh, | |
| closeAddUser, | |
| closeEditUser, | |
| getFormValues, | |
| // Translation | |
| t, | |
| }; | |
| }; | |