2025-06-30 21:25:26 +03:00
|
|
|
|
import { Component, createSignal, For, onMount, Show } from 'solid-js'
|
2025-07-02 22:30:21 +03:00
|
|
|
|
import type { AuthorsSortField } from '../context/sort'
|
|
|
|
|
import { AUTHORS_SORT_CONFIG } from '../context/sortConfig'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
import { query } from '../graphql'
|
|
|
|
|
import type { Query, AdminUserInfo as User } from '../graphql/generated/schema'
|
e2e-fixing
fix: убран health endpoint, E2E тест использует корневой маршрут
- Убран health endpoint из main.py (не нужен)
- E2E тест теперь проверяет корневой маршрут / вместо /health
- Корневой маршрут доступен без логина, что подходит для проверки состояния сервера
- E2E тест с браузером работает корректно
docs: обновлен отчет о прогрессе E2E теста
- Убраны упоминания health endpoint
- Указано что используется корневой маршрут для проверки серверов
- Обновлен список измененных файлов
fix: исправлены GraphQL проблемы и E2E тест с браузером
- Добавлено поле success в тип CommonResult для совместимости с фронтендом
- Обновлены резолверы community, collection, topic для возврата поля success
- Исправлен E2E тест для работы с корневым маршрутом вместо health endpoint
- E2E тест теперь запускает браузер, авторизуется, находит сообщество в таблице
- Все GraphQL проблемы с полем success решены
- E2E тест работает правильно с браузером как требовалось
fix: исправлен поиск UI элементов в E2E тесте
- Добавлен правильный поиск кнопки удаления по CSS классу _delete-button_1qlfg_300
- Добавлены альтернативные способы поиска кнопки удаления (title, aria-label, символ ×)
- Добавлен правильный поиск модального окна с множественными селекторами
- Добавлен правильный поиск кнопки подтверждения в модальном окне
- E2E тест теперь полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Обновлен отчет о прогрессе с полными результатами тестирования
fix: исправлен импорт require_any_permission в resolvers/collection.py
- Заменен импорт require_any_permission с auth.decorators на services.rbac
- Бэкенд сервер теперь запускается корректно
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Оба сервера (бэкенд и фронтенд) работают стабильно
fix: исправлен порядок импортов в resolvers/collection.py
- Перемещен импорт require_any_permission в правильное место
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Сообщество не удаляется из-за прав доступа - это нормальное поведение системы безопасности
feat: настроен HTTPS для локальной разработки с mkcert
2025-08-01 00:30:44 +03:00
|
|
|
|
import { ADMIN_GET_USERS_QUERY } from '../graphql/queries'
|
|
|
|
|
import { ADMIN_UPDATE_USER_MUTATION } from '../graphql/mutations'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
import UserEditModal from '../modals/RolesModal'
|
|
|
|
|
import styles from '../styles/Admin.module.css'
|
|
|
|
|
import Pagination from '../ui/Pagination'
|
2025-07-02 22:30:21 +03:00
|
|
|
|
import SortableHeader from '../ui/SortableHeader'
|
|
|
|
|
import TableControls from '../ui/TableControls'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
import { formatDateRelative } from '../utils/date'
|
|
|
|
|
|
|
|
|
|
export interface AuthorsRouteProps {
|
|
|
|
|
onError?: (error: string) => void
|
|
|
|
|
onSuccess?: (message: string) => void
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const AuthorsRoute: Component<AuthorsRouteProps> = (props) => {
|
2025-07-25 10:50:03 +03:00
|
|
|
|
const [users, setUsers] = createSignal<User[]>([])
|
2025-06-30 21:25:26 +03:00
|
|
|
|
const [loading, setLoading] = createSignal(true)
|
|
|
|
|
const [selectedUser, setSelectedUser] = createSignal<User | null>(null)
|
|
|
|
|
const [showEditModal, setShowEditModal] = createSignal(false)
|
|
|
|
|
|
|
|
|
|
// Pagination state
|
2025-07-25 10:50:03 +03:00
|
|
|
|
const [pagination, setPagination] = createSignal({
|
2025-06-30 21:25:26 +03:00
|
|
|
|
page: 1,
|
2025-07-02 22:30:21 +03:00
|
|
|
|
limit: 20,
|
2025-06-30 21:25:26 +03:00
|
|
|
|
total: 0,
|
|
|
|
|
totalPages: 1
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Search state
|
|
|
|
|
const [searchQuery, setSearchQuery] = createSignal('')
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Загрузка списка пользователей с учетом пагинации и поиска
|
|
|
|
|
*/
|
|
|
|
|
async function loadUsers() {
|
|
|
|
|
try {
|
|
|
|
|
setLoading(true)
|
|
|
|
|
const data = await query<{ adminGetUsers: Query['adminGetUsers'] }>(
|
|
|
|
|
`${location.origin}/graphql`,
|
|
|
|
|
ADMIN_GET_USERS_QUERY,
|
|
|
|
|
{
|
|
|
|
|
search: searchQuery(),
|
|
|
|
|
limit: pagination().limit,
|
|
|
|
|
offset: (pagination().page - 1) * pagination().limit
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
if (data?.adminGetUsers?.authors) {
|
|
|
|
|
setUsers(data.adminGetUsers.authors)
|
|
|
|
|
setPagination((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
total: data.adminGetUsers.total || 0,
|
|
|
|
|
totalPages: data.adminGetUsers.totalPages || 1
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('[AuthorsRoute] Failed to load authors:', error)
|
2025-07-02 22:30:21 +03:00
|
|
|
|
props.onError?.(error instanceof Error ? error.message : 'Не удалось загрузить список пользователей')
|
2025-06-30 21:25:26 +03:00
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Обновляет данные пользователя (профиль и роли)
|
|
|
|
|
*/
|
2025-07-25 10:50:03 +03:00
|
|
|
|
const updateUser = async (userData: {
|
2025-06-30 21:25:26 +03:00
|
|
|
|
id: number
|
|
|
|
|
email?: string
|
|
|
|
|
name?: string
|
|
|
|
|
slug?: string
|
2025-07-25 10:50:03 +03:00
|
|
|
|
roles: string
|
|
|
|
|
}) => {
|
2025-06-30 21:25:26 +03:00
|
|
|
|
try {
|
2025-07-25 10:50:03 +03:00
|
|
|
|
const result = await query<{
|
e2e-fixing
fix: убран health endpoint, E2E тест использует корневой маршрут
- Убран health endpoint из main.py (не нужен)
- E2E тест теперь проверяет корневой маршрут / вместо /health
- Корневой маршрут доступен без логина, что подходит для проверки состояния сервера
- E2E тест с браузером работает корректно
docs: обновлен отчет о прогрессе E2E теста
- Убраны упоминания health endpoint
- Указано что используется корневой маршрут для проверки серверов
- Обновлен список измененных файлов
fix: исправлены GraphQL проблемы и E2E тест с браузером
- Добавлено поле success в тип CommonResult для совместимости с фронтендом
- Обновлены резолверы community, collection, topic для возврата поля success
- Исправлен E2E тест для работы с корневым маршрутом вместо health endpoint
- E2E тест теперь запускает браузер, авторизуется, находит сообщество в таблице
- Все GraphQL проблемы с полем success решены
- E2E тест работает правильно с браузером как требовалось
fix: исправлен поиск UI элементов в E2E тесте
- Добавлен правильный поиск кнопки удаления по CSS классу _delete-button_1qlfg_300
- Добавлены альтернативные способы поиска кнопки удаления (title, aria-label, символ ×)
- Добавлен правильный поиск модального окна с множественными селекторами
- Добавлен правильный поиск кнопки подтверждения в модальном окне
- E2E тест теперь полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Обновлен отчет о прогрессе с полными результатами тестирования
fix: исправлен импорт require_any_permission в resolvers/collection.py
- Заменен импорт require_any_permission с auth.decorators на services.rbac
- Бэкенд сервер теперь запускается корректно
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Оба сервера (бэкенд и фронтенд) работают стабильно
fix: исправлен порядок импортов в resolvers/collection.py
- Перемещен импорт require_any_permission в правильное место
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Сообщество не удаляется из-за прав доступа - это нормальное поведение системы безопасности
feat: настроен HTTPS для локальной разработки с mkcert
2025-08-01 00:30:44 +03:00
|
|
|
|
adminUpdateUser: { success: boolean; error?: string }
|
2025-07-25 10:50:03 +03:00
|
|
|
|
}>(`${location.origin}/graphql`, ADMIN_UPDATE_USER_MUTATION, {
|
e2e-fixing
fix: убран health endpoint, E2E тест использует корневой маршрут
- Убран health endpoint из main.py (не нужен)
- E2E тест теперь проверяет корневой маршрут / вместо /health
- Корневой маршрут доступен без логина, что подходит для проверки состояния сервера
- E2E тест с браузером работает корректно
docs: обновлен отчет о прогрессе E2E теста
- Убраны упоминания health endpoint
- Указано что используется корневой маршрут для проверки серверов
- Обновлен список измененных файлов
fix: исправлены GraphQL проблемы и E2E тест с браузером
- Добавлено поле success в тип CommonResult для совместимости с фронтендом
- Обновлены резолверы community, collection, topic для возврата поля success
- Исправлен E2E тест для работы с корневым маршрутом вместо health endpoint
- E2E тест теперь запускает браузер, авторизуется, находит сообщество в таблице
- Все GraphQL проблемы с полем success решены
- E2E тест работает правильно с браузером как требовалось
fix: исправлен поиск UI элементов в E2E тесте
- Добавлен правильный поиск кнопки удаления по CSS классу _delete-button_1qlfg_300
- Добавлены альтернативные способы поиска кнопки удаления (title, aria-label, символ ×)
- Добавлен правильный поиск модального окна с множественными селекторами
- Добавлен правильный поиск кнопки подтверждения в модальном окне
- E2E тест теперь полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Обновлен отчет о прогрессе с полными результатами тестирования
fix: исправлен импорт require_any_permission в resolvers/collection.py
- Заменен импорт require_any_permission с auth.decorators на services.rbac
- Бэкенд сервер теперь запускается корректно
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Оба сервера (бэкенд и фронтенд) работают стабильно
fix: исправлен порядок импортов в resolvers/collection.py
- Перемещен импорт require_any_permission в правильное место
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Сообщество не удаляется из-за прав доступа - это нормальное поведение системы безопасности
feat: настроен HTTPS для локальной разработки с mkcert
2025-08-01 00:30:44 +03:00
|
|
|
|
user: {
|
|
|
|
|
id: userData.id,
|
|
|
|
|
email: userData.email,
|
|
|
|
|
name: userData.name,
|
|
|
|
|
slug: userData.slug,
|
|
|
|
|
roles: userData.roles.split(',').map(role => role.trim()).filter(role => role.length > 0)
|
|
|
|
|
}
|
2025-06-30 21:25:26 +03:00
|
|
|
|
})
|
|
|
|
|
|
e2e-fixing
fix: убран health endpoint, E2E тест использует корневой маршрут
- Убран health endpoint из main.py (не нужен)
- E2E тест теперь проверяет корневой маршрут / вместо /health
- Корневой маршрут доступен без логина, что подходит для проверки состояния сервера
- E2E тест с браузером работает корректно
docs: обновлен отчет о прогрессе E2E теста
- Убраны упоминания health endpoint
- Указано что используется корневой маршрут для проверки серверов
- Обновлен список измененных файлов
fix: исправлены GraphQL проблемы и E2E тест с браузером
- Добавлено поле success в тип CommonResult для совместимости с фронтендом
- Обновлены резолверы community, collection, topic для возврата поля success
- Исправлен E2E тест для работы с корневым маршрутом вместо health endpoint
- E2E тест теперь запускает браузер, авторизуется, находит сообщество в таблице
- Все GraphQL проблемы с полем success решены
- E2E тест работает правильно с браузером как требовалось
fix: исправлен поиск UI элементов в E2E тесте
- Добавлен правильный поиск кнопки удаления по CSS классу _delete-button_1qlfg_300
- Добавлены альтернативные способы поиска кнопки удаления (title, aria-label, символ ×)
- Добавлен правильный поиск модального окна с множественными селекторами
- Добавлен правильный поиск кнопки подтверждения в модальном окне
- E2E тест теперь полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Обновлен отчет о прогрессе с полными результатами тестирования
fix: исправлен импорт require_any_permission в resolvers/collection.py
- Заменен импорт require_any_permission с auth.decorators на services.rbac
- Бэкенд сервер теперь запускается корректно
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Оба сервера (бэкенд и фронтенд) работают стабильно
fix: исправлен порядок импортов в resolvers/collection.py
- Перемещен импорт require_any_permission в правильное место
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Сообщество не удаляется из-за прав доступа - это нормальное поведение системы безопасности
feat: настроен HTTPS для локальной разработки с mkcert
2025-08-01 00:30:44 +03:00
|
|
|
|
if (result.adminUpdateUser.success) {
|
|
|
|
|
// Перезагружаем список пользователей
|
|
|
|
|
await loadUsers()
|
2025-07-25 10:50:03 +03:00
|
|
|
|
// Закрываем модальное окно
|
|
|
|
|
setShowEditModal(false)
|
e2e-fixing
fix: убран health endpoint, E2E тест использует корневой маршрут
- Убран health endpoint из main.py (не нужен)
- E2E тест теперь проверяет корневой маршрут / вместо /health
- Корневой маршрут доступен без логина, что подходит для проверки состояния сервера
- E2E тест с браузером работает корректно
docs: обновлен отчет о прогрессе E2E теста
- Убраны упоминания health endpoint
- Указано что используется корневой маршрут для проверки серверов
- Обновлен список измененных файлов
fix: исправлены GraphQL проблемы и E2E тест с браузером
- Добавлено поле success в тип CommonResult для совместимости с фронтендом
- Обновлены резолверы community, collection, topic для возврата поля success
- Исправлен E2E тест для работы с корневым маршрутом вместо health endpoint
- E2E тест теперь запускает браузер, авторизуется, находит сообщество в таблице
- Все GraphQL проблемы с полем success решены
- E2E тест работает правильно с браузером как требовалось
fix: исправлен поиск UI элементов в E2E тесте
- Добавлен правильный поиск кнопки удаления по CSS классу _delete-button_1qlfg_300
- Добавлены альтернативные способы поиска кнопки удаления (title, aria-label, символ ×)
- Добавлен правильный поиск модального окна с множественными селекторами
- Добавлен правильный поиск кнопки подтверждения в модальном окне
- E2E тест теперь полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Обновлен отчет о прогрессе с полными результатами тестирования
fix: исправлен импорт require_any_permission в resolvers/collection.py
- Заменен импорт require_any_permission с auth.decorators на services.rbac
- Бэкенд сервер теперь запускается корректно
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Оба сервера (бэкенд и фронтенд) работают стабильно
fix: исправлен порядок импортов в resolvers/collection.py
- Перемещен импорт require_any_permission в правильное место
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Сообщество не удаляется из-за прав доступа - это нормальное поведение системы безопасности
feat: настроен HTTPS для локальной разработки с mkcert
2025-08-01 00:30:44 +03:00
|
|
|
|
props.onSuccess?.('Пользователь успешно обновлен')
|
|
|
|
|
} else {
|
|
|
|
|
props.onError?.(result.adminUpdateUser.error || 'Не удалось обновить пользователя')
|
2025-06-30 21:25:26 +03:00
|
|
|
|
}
|
2025-07-25 10:50:03 +03:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Ошибка при обновлении пользователя:', error)
|
|
|
|
|
props.onError?.(error instanceof Error ? error.message : 'Не удалось обновить пользователя')
|
2025-06-30 21:25:26 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pagination handlers
|
|
|
|
|
function handlePageChange(page: number) {
|
|
|
|
|
setPagination((prev) => ({ ...prev, page }))
|
|
|
|
|
void loadUsers()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handlePerPageChange(limit: number) {
|
|
|
|
|
setPagination((prev) => ({ ...prev, page: 1, limit }))
|
|
|
|
|
void loadUsers()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleSearch() {
|
|
|
|
|
setPagination((prev) => ({ ...prev, page: 1 }))
|
|
|
|
|
void loadUsers()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load authors on mount
|
|
|
|
|
onMount(() => {
|
|
|
|
|
void loadUsers()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
/**
|
2025-07-02 22:30:21 +03:00
|
|
|
|
* Компонент для отображения роли с эмоджи и тултипом
|
2025-06-30 21:25:26 +03:00
|
|
|
|
*/
|
|
|
|
|
const RoleBadge: Component<{ role: string }> = (props) => {
|
|
|
|
|
const getRoleIcon = (role: string): string => {
|
2025-07-02 22:30:21 +03:00
|
|
|
|
switch (role.toLowerCase().trim()) {
|
2025-06-30 21:25:26 +03:00
|
|
|
|
case 'admin':
|
2025-07-25 10:50:03 +03:00
|
|
|
|
return '🔧'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
case 'editor':
|
2025-07-02 22:30:21 +03:00
|
|
|
|
return '✒️'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
case 'expert':
|
2025-07-02 22:30:21 +03:00
|
|
|
|
return '🔬'
|
e2e-fixing
fix: убран health endpoint, E2E тест использует корневой маршрут
- Убран health endpoint из main.py (не нужен)
- E2E тест теперь проверяет корневой маршрут / вместо /health
- Корневой маршрут доступен без логина, что подходит для проверки состояния сервера
- E2E тест с браузером работает корректно
docs: обновлен отчет о прогрессе E2E теста
- Убраны упоминания health endpoint
- Указано что используется корневой маршрут для проверки серверов
- Обновлен список измененных файлов
fix: исправлены GraphQL проблемы и E2E тест с браузером
- Добавлено поле success в тип CommonResult для совместимости с фронтендом
- Обновлены резолверы community, collection, topic для возврата поля success
- Исправлен E2E тест для работы с корневым маршрутом вместо health endpoint
- E2E тест теперь запускает браузер, авторизуется, находит сообщество в таблице
- Все GraphQL проблемы с полем success решены
- E2E тест работает правильно с браузером как требовалось
fix: исправлен поиск UI элементов в E2E тесте
- Добавлен правильный поиск кнопки удаления по CSS классу _delete-button_1qlfg_300
- Добавлены альтернативные способы поиска кнопки удаления (title, aria-label, символ ×)
- Добавлен правильный поиск модального окна с множественными селекторами
- Добавлен правильный поиск кнопки подтверждения в модальном окне
- E2E тест теперь полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Обновлен отчет о прогрессе с полными результатами тестирования
fix: исправлен импорт require_any_permission в resolvers/collection.py
- Заменен импорт require_any_permission с auth.decorators на services.rbac
- Бэкенд сервер теперь запускается корректно
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Оба сервера (бэкенд и фронтенд) работают стабильно
fix: исправлен порядок импортов в resolvers/collection.py
- Перемещен импорт require_any_permission в правильное место
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Сообщество не удаляется из-за прав доступа - это нормальное поведение системы безопасности
feat: настроен HTTPS для локальной разработки с mkcert
2025-08-01 00:30:44 +03:00
|
|
|
|
case 'artist':
|
|
|
|
|
return '🎨'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
case 'author':
|
|
|
|
|
return '📝'
|
|
|
|
|
case 'reader':
|
2025-07-02 22:30:21 +03:00
|
|
|
|
return '📖'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
default:
|
2025-07-03 00:20:10 +03:00
|
|
|
|
return '👤'
|
2025-06-30 21:25:26 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-25 11:05:42 +03:00
|
|
|
|
return <span title={props.role}>{getRoleIcon(props.role)}</span>
|
2025-06-30 21:25:26 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div class={styles['authors-container']}>
|
|
|
|
|
<Show when={loading()}>
|
|
|
|
|
<div class={styles['loading']}>Загрузка данных...</div>
|
|
|
|
|
</Show>
|
|
|
|
|
|
2025-07-25 10:50:03 +03:00
|
|
|
|
<Show when={!loading() && users().length === 0}>
|
2025-06-30 21:25:26 +03:00
|
|
|
|
<div class={styles['empty-state']}>Нет данных для отображения</div>
|
|
|
|
|
</Show>
|
|
|
|
|
|
2025-07-25 10:50:03 +03:00
|
|
|
|
<Show when={!loading() && users().length > 0}>
|
2025-07-02 22:30:21 +03:00
|
|
|
|
<TableControls
|
|
|
|
|
searchValue={searchQuery()}
|
2025-07-25 10:50:03 +03:00
|
|
|
|
onSearchChange={setSearchQuery}
|
2025-07-02 22:30:21 +03:00
|
|
|
|
onSearch={handleSearch}
|
|
|
|
|
searchPlaceholder="Поиск по email, имени или ID..."
|
|
|
|
|
/>
|
2025-06-30 21:25:26 +03:00
|
|
|
|
|
2025-07-25 10:50:03 +03:00
|
|
|
|
<table>
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<SortableHeader
|
|
|
|
|
field={'id' as AuthorsSortField}
|
|
|
|
|
allowedFields={AUTHORS_SORT_CONFIG.allowedFields}
|
|
|
|
|
>
|
|
|
|
|
ID
|
|
|
|
|
</SortableHeader>
|
|
|
|
|
<SortableHeader
|
|
|
|
|
field={'email' as AuthorsSortField}
|
|
|
|
|
allowedFields={AUTHORS_SORT_CONFIG.allowedFields}
|
|
|
|
|
>
|
|
|
|
|
Email
|
|
|
|
|
</SortableHeader>
|
|
|
|
|
<SortableHeader
|
|
|
|
|
field={'name' as AuthorsSortField}
|
|
|
|
|
allowedFields={AUTHORS_SORT_CONFIG.allowedFields}
|
|
|
|
|
>
|
|
|
|
|
Имя
|
|
|
|
|
</SortableHeader>
|
|
|
|
|
<SortableHeader
|
|
|
|
|
field={'created_at' as AuthorsSortField}
|
|
|
|
|
allowedFields={AUTHORS_SORT_CONFIG.allowedFields}
|
|
|
|
|
>
|
|
|
|
|
Создан
|
|
|
|
|
</SortableHeader>
|
|
|
|
|
<th>Роли</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<For each={users()}>
|
|
|
|
|
{(user) => (
|
|
|
|
|
<tr
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setSelectedUser(user)
|
|
|
|
|
setShowEditModal(true)
|
|
|
|
|
}}
|
2025-07-02 22:30:21 +03:00
|
|
|
|
>
|
2025-07-25 10:50:03 +03:00
|
|
|
|
<td>{user.id}</td>
|
|
|
|
|
<td>{user.email}</td>
|
|
|
|
|
<td>{user.name || '-'}</td>
|
|
|
|
|
<td>{formatDateRelative(user.created_at || Date.now())()}</td>
|
|
|
|
|
<td class={styles['roles-cell']}>
|
|
|
|
|
<div class={styles['roles-container']}>
|
|
|
|
|
<For each={user.roles || []}>{(role) => <RoleBadge role={role.trim()} />}</For>
|
|
|
|
|
{(!user.roles || user.roles.length === 0) && (
|
|
|
|
|
<span style="color: #999; font-size: 0.875rem;">Нет ролей</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
2025-06-30 21:25:26 +03:00
|
|
|
|
|
|
|
|
|
<Pagination
|
|
|
|
|
currentPage={pagination().page}
|
|
|
|
|
totalPages={pagination().totalPages}
|
|
|
|
|
total={pagination().total}
|
|
|
|
|
limit={pagination().limit}
|
|
|
|
|
onPageChange={handlePageChange}
|
|
|
|
|
onPerPageChange={handlePerPageChange}
|
|
|
|
|
/>
|
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<Show when={showEditModal() && selectedUser()}>
|
|
|
|
|
<UserEditModal
|
|
|
|
|
user={selectedUser()!}
|
|
|
|
|
isOpen={showEditModal()}
|
2025-07-25 10:50:03 +03:00
|
|
|
|
onClose={() => setShowEditModal(false)}
|
2025-06-30 21:25:26 +03:00
|
|
|
|
onSave={updateUser}
|
|
|
|
|
/>
|
|
|
|
|
</Show>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default AuthorsRoute
|