fix(users): fieldValues в реальном обработчике /api/users/list + горизонтальный скролл таблицы

Причина «поля профиля не отображаются»: /api/users/list обслуживает СТАРЫЙ
обработчик в auth.users.routes.ts (зарегистрирован раньше дубля handleListUsers
в user.routes.ts — проверено: в ответе нет total/pageSize). includeFieldValues
добавлен в оба, но реальный — теперь тоже отдаёт fieldValues.
Плюс overflow-x-auto на контейнере таблицы — прокрутка при переполнении колонок.
This commit is contained in:
2026-09-29 15:32:47 +03:00
parent c0011b49a3
commit 4d1dc2b6f9
2 changed files with 21 additions and 1 deletions

View File

@@ -1091,7 +1091,7 @@ const UsersPage = () => {
<ActiveFilterBadges filters={filters} sort={sort} columnLabels={userColumnLabels} onRemoveFilter={clearFilter} onRemoveSort={clearSort} onClearAll={clearAll} /> <ActiveFilterBadges filters={filters} sort={sort} columnLabels={userColumnLabels} onRemoveFilter={clearFilter} onRemoveSort={clearSort} onClearAll={clearAll} />
</div> </div>
)} )}
<div className="p-3"> <div className="p-3 overflow-x-auto">
<div className="flex justify-end mb-2"> <div className="flex justify-end mb-2">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>

View File

@@ -5,6 +5,9 @@ import { authService } from "../services/auth.service";
import { authenticateToken, requirePermission, type AuthenticatedRequest } from "../middleware/auth.middleware"; import { authenticateToken, requirePermission, type AuthenticatedRequest } from "../middleware/auth.middleware";
import { tenantIsolation } from "../middleware/tenant.middleware"; import { tenantIsolation } from "../middleware/tenant.middleware";
import { validateRequest } from "../middleware/validation.middleware"; import { validateRequest } from "../middleware/validation.middleware";
import { db } from "../db";
import { inArray } from "drizzle-orm";
import { userProfileFieldValues } from "@shared/schema";
import { import {
createUserCustomFieldSchema, updateUserCustomFieldSchema, createUserCustomFieldSchema, updateUserCustomFieldSchema,
setUserCustomValueSchema, setUserCustomValueSchema,
@@ -198,6 +201,22 @@ export function registerUserManagementRoutes(router: Router): void {
return ''; return '';
}; };
// Значения кастомных полей профиля — для реестра пользователей (выбор колонок).
// ВНИМАНИЕ: этот обработчик /api/users/list фактически обслуживает запросы
// (зарегистрирован раньше дубля в user.routes.ts handleListUsers).
const includeFieldValues = req.query.includeFieldValues === '1';
const fieldValuesMap = new Map<number, Record<number, unknown>>();
if (includeFieldValues && users.length > 0) {
const fvRows = await db
.select({ userId: userProfileFieldValues.userId, fieldId: userProfileFieldValues.fieldId, value: userProfileFieldValues.value })
.from(userProfileFieldValues)
.where(inArray(userProfileFieldValues.userId, users.map(u => u.id)));
for (const row of fvRows) {
if (!fieldValuesMap.has(row.userId)) fieldValuesMap.set(row.userId, {});
fieldValuesMap.get(row.userId)![row.fieldId] = row.value;
}
}
let safeUsers = users.map(user => ({ let safeUsers = users.map(user => ({
id: user.id, id: user.id,
email: user.email, email: user.email,
@@ -212,6 +231,7 @@ export function registerUserManagementRoutes(router: Router): void {
lastActivityAt: user.lastActivityAt, lastActivityAt: user.lastActivityAt,
createdAt: user.createdAt, createdAt: user.createdAt,
organizationalRoles: roleMembersMap.get(user.id) || [], organizationalRoles: roleMembersMap.get(user.id) || [],
...(includeFieldValues ? { fieldValues: fieldValuesMap.get(user.id) || {} } : {}),
})); }));
Object.entries(filtersObj).forEach(([col, val]) => { Object.entries(filtersObj).forEach(([col, val]) => {