fix: поиск сотрудника в маршруте без учёта регистра
Фильтр SharePoint substringof по Title пользователей сайта для кириллицы чувствителен к регистру: «тимур» не находил «Тимур Городецкий». Теперь ищутся сразу несколько написаний (как введено, строчными, с заглавной каждого слова) и по email. Касается всех полей выбора сотрудника в маршруте: делегирование, добавление согласующего, замена исполнителя. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import { IApprovalRow } from './models/IApprovalRow';
|
||||
import { IMatrixRow } from './models/IMatrixRow';
|
||||
import { ISiteUser } from './models/ISiteUser';
|
||||
import { APPROVAL_PHASE, REQUEST_STATUS } from './models/statuses';
|
||||
import { userSearchVariants } from './userSearchVariants';
|
||||
|
||||
// Внутренние имена колонок списка согласования (создаются провижинингом).
|
||||
const FIELDS = {
|
||||
@@ -336,13 +337,18 @@ export class ApprovalListService {
|
||||
});
|
||||
}
|
||||
|
||||
// Поиск пользователей сайта по части имени — для пикера согласующего.
|
||||
// Поиск пользователей сайта по части имени или почты — для пикера согласующего.
|
||||
// Несколько написаний сразу: substringof по Title для кириллицы чувствителен к
|
||||
// регистру (см. userSearchVariants). Почта в SharePoint хранится строчными —
|
||||
// по ней достаточно строчного варианта.
|
||||
public async searchUsers(query: string): Promise<ISiteUser[]> {
|
||||
const q = query.trim();
|
||||
if (q.length < 2) return [];
|
||||
const escaped = q.replace(/'/g, "''");
|
||||
const escape = (s: string): string => s.replace(/'/g, "''");
|
||||
const titleClauses = userSearchVariants(q).map((v) => `substringof('${escape(v)}',Title)`);
|
||||
const emailClause = `substringof('${escape(q.toLowerCase())}',Email)`;
|
||||
const users = (await getSP()
|
||||
.web.siteUsers.filter(`substringof('${escaped}',Title) and PrincipalType eq 1`)
|
||||
.web.siteUsers.filter(`(${titleClauses.concat(emailClause).join(' or ')}) and PrincipalType eq 1`)
|
||||
.select('Id', 'Title', 'Email', 'LoginName')
|
||||
.top(10)()) as Array<Record<string, unknown>>;
|
||||
return users.map((u) => ({
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { userSearchVariants } from './userSearchVariants';
|
||||
|
||||
describe('userSearchVariants', () => {
|
||||
it('строчный ввод даёт и вариант с заглавной — так ФИО хранятся в SharePoint', () => {
|
||||
expect(userSearchVariants('тимур')).toEqual(['тимур', 'Тимур']);
|
||||
});
|
||||
|
||||
it('заглавной делается каждое слово', () => {
|
||||
expect(userSearchVariants('тимур городецкий')).toContain('Тимур Городецкий');
|
||||
});
|
||||
|
||||
it('ввод капсом даёт и строчный, и «Как В Имени»', () => {
|
||||
expect(userSearchVariants('ТИМУР')).toEqual(['ТИМУР', 'тимур', 'Тимур']);
|
||||
});
|
||||
|
||||
it('без повторов, если ввод уже в нужном виде', () => {
|
||||
expect(userSearchVariants('Тимур')).toEqual(['Тимур', 'тимур']);
|
||||
});
|
||||
|
||||
it('пустой ввод — пусто', () => {
|
||||
expect(userSearchVariants(' ')).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Варианты написания запроса для поиска сотрудника (ApprovalListService.searchUsers).
|
||||
*
|
||||
* Фильтр SharePoint `substringof(…, Title)` по пользователям сайта для
|
||||
* кириллицы чувствителен к регистру: «тимур» не находит «Тимур Городецкий».
|
||||
* Поэтому ищем сразу несколько написаний — как введено, строчными и «Как В
|
||||
* Имени» (с заглавной каждое слово, так ФИО и хранятся в Title). Повторы
|
||||
* убираются, чтобы не раздувать фильтр.
|
||||
*/
|
||||
export function userSearchVariants(query: string): string[] {
|
||||
const typed = query.trim();
|
||||
if (!typed) return [];
|
||||
const lower = typed.toLowerCase();
|
||||
const capitalized = lower
|
||||
.split(/\s+/)
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
|
||||
const variants: string[] = [];
|
||||
[typed, lower, capitalized].forEach((v) => {
|
||||
if (variants.indexOf(v) < 0) variants.push(v);
|
||||
});
|
||||
return variants;
|
||||
}
|
||||
Reference in New Issue
Block a user