Правка ошибок #11
@@ -26,6 +26,7 @@ import {
|
|||||||
unassignedStepMessage
|
unassignedStepMessage
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -79,7 +80,7 @@ const ClearanceForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
useRequestTypeId,
|
useRequestTypeId,
|
||||||
APPROVAL_PHASE
|
APPROVAL_PHASE
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -105,7 +106,7 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
IAttachmentInfo
|
IAttachmentInfo
|
||||||
} from '../../shared/attachments/attachments.service';
|
} from '../../shared/attachments/attachments.service';
|
||||||
import { effectiveUserEmail } from '../../shared/impersonation';
|
import { effectiveUserEmail } from '../../shared/impersonation';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
@@ -91,7 +92,7 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { navigate } from '../../shared/routing';
|
import { navigate } from '../../shared/routing';
|
||||||
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -117,7 +118,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import {
|
|||||||
IAttachmentInfo
|
IAttachmentInfo
|
||||||
} from '../../shared/attachments/attachments.service';
|
} from '../../shared/attachments/attachments.service';
|
||||||
import { effectiveUserEmail } from '../../shared/impersonation';
|
import { effectiveUserEmail } from '../../shared/impersonation';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
@@ -88,7 +89,7 @@ const RecruitingSelectionForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
useRequestTypeId
|
useRequestTypeId
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -83,7 +84,7 @@ const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ cont
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import {
|
|||||||
IAttachmentInfo
|
IAttachmentInfo
|
||||||
} from '../../shared/attachments/attachments.service';
|
} from '../../shared/attachments/attachments.service';
|
||||||
import { effectiveUserEmail } from '../../shared/impersonation';
|
import { effectiveUserEmail } from '../../shared/impersonation';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
@@ -105,7 +106,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
REQUEST_STATUS
|
REQUEST_STATUS
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -122,7 +123,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey,
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
IAttachmentInfo
|
IAttachmentInfo
|
||||||
} from '../../shared/attachments/attachments.service';
|
} from '../../shared/attachments/attachments.service';
|
||||||
import { effectiveUserEmail } from '../../shared/impersonation';
|
import { effectiveUserEmail } from '../../shared/impersonation';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
@@ -104,7 +105,7 @@ const TmcTransferForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
APPROVAL_PHASE
|
APPROVAL_PHASE
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -107,7 +108,7 @@ const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, for
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
resolveWriteListId
|
resolveWriteListId
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -78,7 +79,7 @@ const UnpaidLeaveForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
notifyActiveStep,
|
notifyActiveStep,
|
||||||
useRequestTypeId
|
useRequestTypeId
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -77,7 +78,7 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
unassignedStepMessage
|
unassignedStepMessage
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -78,7 +79,7 @@ const VacationForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
notifyActiveStep,
|
notifyActiveStep,
|
||||||
useRequestTypeId
|
useRequestTypeId
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -77,7 +78,7 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
IAttachmentInfo
|
IAttachmentInfo
|
||||||
} from '../../shared/attachments/attachments.service';
|
} from '../../shared/attachments/attachments.service';
|
||||||
import { effectiveUserEmail } from '../../shared/impersonation';
|
import { effectiveUserEmail } from '../../shared/impersonation';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import { IRequestFormProps } from '../../models/types';
|
import { IRequestFormProps } from '../../models/types';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
@@ -93,7 +94,7 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
submit.setError(`Не удалось загрузить заявку №${editId}: ${(e as Error).message}`);
|
submit.setError(`Не удалось загрузить заявку №${editId}: ${friendlyErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
APPROVAL_PHASE
|
APPROVAL_PHASE
|
||||||
} from '../../shared/approval';
|
} from '../../shared/approval';
|
||||||
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
|
||||||
|
import { friendlyErrorMessage } from '../../shared/diagnostics';
|
||||||
import {
|
import {
|
||||||
approvalListTitle,
|
approvalListTitle,
|
||||||
approvalListTitleForListId,
|
approvalListTitleForListId,
|
||||||
@@ -122,7 +123,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (alive) {
|
if (alive) {
|
||||||
setError(`Не удалось загрузить заявку №${itemId}: ${(e as Error).message}`);
|
setError(`Не удалось загрузить заявку №${itemId}: ${friendlyErrorMessage(e)}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -52,6 +52,42 @@ export function describeReason(reason: unknown): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PnPjs/SharePoint кладёт в Error.message текст ответа сервера целиком —
|
||||||
|
// например: `Error making HttpClient request in queryable [404] ::>
|
||||||
|
// {"odata.error":{"message":{"value":"Элемент не существует..."}}}`. Пока это
|
||||||
|
// строка, а не распарсенный JSON, русские буквы в ней остаются как литеральные
|
||||||
|
// escape-последовательности `Эл...`, и в UI вместо кириллицы видно
|
||||||
|
// набор из "\u". Достаём odata.error.message.value через JSON.parse — сам
|
||||||
|
// парсер раскодирует escape-последовательности обратно в текст.
|
||||||
|
// SharePoint отдаёт этот же текст и когда элемент правда удалён, и когда у
|
||||||
|
// пользователя просто нет прав на список/элемент (сервер прячет 403 за 404,
|
||||||
|
// чтобы не подтверждать существование элемента посторонним). По одному
|
||||||
|
// тексту эти два случая не различить, а "нет доступа" на практике встречается
|
||||||
|
// куда чаще, чем совпадение по времени с удалением — поэтому подменяем
|
||||||
|
// формулировку на более вероятную причину.
|
||||||
|
const ITEM_NOT_FOUND = 'Элемент не существует. Возможно, он был удален другим пользователем.';
|
||||||
|
const NO_ACCESS_HINT =
|
||||||
|
'Элемент не найден. Скорее всего, у вас нет доступа к этому списку или элементу (либо он был удалён).';
|
||||||
|
|
||||||
|
export function friendlyErrorMessage(e: unknown): string {
|
||||||
|
const message = e instanceof Error ? e.message : String(e);
|
||||||
|
const start = message.indexOf('{');
|
||||||
|
const end = message.lastIndexOf('}');
|
||||||
|
if (start !== -1 && end > start) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(message.slice(start, end + 1)) as {
|
||||||
|
'odata.error'?: { message?: { value?: string } };
|
||||||
|
};
|
||||||
|
const value = parsed['odata.error']?.message?.value;
|
||||||
|
if (value === ITEM_NOT_FOUND) return NO_ACCESS_HINT;
|
||||||
|
if (value) return value;
|
||||||
|
} catch {
|
||||||
|
// Тело не JSON (или не то, что ожидали) — отдаём исходное сообщение.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
function logError(kind: string, reason: unknown): void {
|
function logError(kind: string, reason: unknown): void {
|
||||||
console.error(`${PREFIX} ${kind}: ${describeReason(reason)}`);
|
console.error(`${PREFIX} ${kind}: ${describeReason(reason)}`);
|
||||||
// Стек и объект — отдельными аргументами: так консоль браузера даёт
|
// Стек и объект — отдельными аргументами: так консоль браузера даёт
|
||||||
|
|||||||
Reference in New Issue
Block a user