Merge branch 'dev' of gitea.pena:PenaSide/UIKit into dev
Some checks failed
CreateVersion / BumpVersion (push) Has been cancelled
Some checks failed
CreateVersion / BumpVersion (push) Has been cancelled
This commit is contained in:
commit
784bd57410
@ -1,49 +1,27 @@
|
|||||||
import axios, { AxiosResponse, Method, ResponseType } from "axios";
|
import axios, { AxiosResponse, Method, ResponseType } from "axios";
|
||||||
import { getAuthToken, setAuthToken } from "../stores/auth";
|
import { getAuthToken, setAuthToken } from "../stores/auth";
|
||||||
|
import { Ticket, clearErrorHandlingConfig } from "..";
|
||||||
export interface MakeRequestConfig {
|
|
||||||
getAuthToken: () => string | undefined;
|
|
||||||
setAuthToken: (token: string) => void;
|
|
||||||
refreshUrl: string;
|
|
||||||
logoutFn: () => void;
|
|
||||||
handleComponentError?: (error: Error, info?: any) => void;
|
|
||||||
clearAuthDataFn?: () => void;
|
|
||||||
clearErrorHandlingConfig?: () => void;
|
|
||||||
allowedDomains?: string[];
|
|
||||||
debugSecretKey?: string;
|
|
||||||
logErrorFn?: (message: string, error?: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
let makeRequestConfig: MakeRequestConfig | null = null;
|
let makeRequestConfig: MakeRequestConfig | null = null;
|
||||||
|
|
||||||
|
export interface MakeRequestConfig {
|
||||||
|
logoutFn: () => void;
|
||||||
|
handleComponentError?: (error: Error, info: any, getTickets: () => Ticket[]) => void;
|
||||||
|
getTickets?: () => Ticket[];
|
||||||
|
}
|
||||||
|
|
||||||
export function createMakeRequestConfig(
|
export function createMakeRequestConfig(
|
||||||
getAuthToken: () => string | undefined,
|
|
||||||
setAuthToken: (token: string) => void,
|
|
||||||
refreshUrl: string,
|
|
||||||
logoutFn?: () => void,
|
logoutFn?: () => void,
|
||||||
handleComponentError?: (error: Error, info?: any) => void,
|
handleComponentError?: (error: Error, info: any, getTickets: () => Ticket[]) => void,
|
||||||
clearAuthDataFn?: () => void,
|
getTickets?: () => Ticket[]
|
||||||
clearErrorHandlingConfig?: () => void,
|
|
||||||
allowedDomains?: string[],
|
|
||||||
debugSecretKey?: string,
|
|
||||||
logErrorFn?: (message: string, error?: any) => void,
|
|
||||||
) {
|
) {
|
||||||
makeRequestConfig = {
|
makeRequestConfig = {
|
||||||
getAuthToken,
|
|
||||||
setAuthToken,
|
|
||||||
refreshUrl,
|
|
||||||
logoutFn: () => {
|
logoutFn: () => {
|
||||||
clearMakeRequestConfig();
|
clearErrorHandlingConfig();
|
||||||
if (typeof clearErrorHandlingConfig === 'function') clearErrorHandlingConfig();
|
|
||||||
if (logoutFn) logoutFn();
|
if (logoutFn) logoutFn();
|
||||||
},
|
},
|
||||||
handleComponentError,
|
handleComponentError,
|
||||||
clearAuthDataFn,
|
getTickets,
|
||||||
clearErrorHandlingConfig,
|
|
||||||
allowedDomains,
|
|
||||||
debugSecretKey,
|
|
||||||
logErrorFn,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +29,6 @@ export function getMakeRequestConfig(): MakeRequestConfig | null {
|
|||||||
return makeRequestConfig;
|
return makeRequestConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearMakeRequestConfig() {
|
|
||||||
makeRequestConfig = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function makeRequest<TRequest = unknown, TResponse = unknown>({
|
export async function makeRequest<TRequest = unknown, TResponse = unknown>({
|
||||||
method = "post",
|
method = "post",
|
||||||
url,
|
url,
|
||||||
@ -129,15 +103,16 @@ export async function makeRequest<TRequest = unknown, TResponse = unknown>({
|
|||||||
const errorMessage = `HTTP ${error.response.status}: ${error.response?.data?.message || error.message}`;
|
const errorMessage = `HTTP ${error.response.status}: ${error.response?.data?.message || error.message}`;
|
||||||
const httpError = new Error(errorMessage);
|
const httpError = new Error(errorMessage);
|
||||||
httpError.stack = error.stack;
|
httpError.stack = error.stack;
|
||||||
config.handleComponentError(httpError, { componentStack: null });
|
// Передаем getTickets как callback
|
||||||
|
config.handleComponentError(httpError, { componentStack: null }, config.getTickets || (() => []));
|
||||||
}
|
}
|
||||||
// refreshToken is empty
|
// refreshToken is empty
|
||||||
if (
|
if (
|
||||||
error.response?.status === 400 &&
|
error.response?.status === 400 &&
|
||||||
error.response?.data?.message === "refreshToken is empty" &&
|
error.response?.data?.message === "refreshToken is empty" &&
|
||||||
config?.clearAuthDataFn
|
config?.logoutFn
|
||||||
) {
|
) {
|
||||||
config.clearAuthDataFn();
|
config.logoutFn();
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
|
|
||||||
import { ErrorInfo } from "react";
|
import { ErrorInfo } from "react";
|
||||||
import { Ticket, createTicket, getAuthToken, sendTicketMessage } from "..";
|
import { Ticket, createTicket, getAuthToken, sendTicketMessage } from "..";
|
||||||
|
|
||||||
let errorsQueue: ComponentError[] = [];
|
let errorsQueue: ComponentError[] = [];
|
||||||
let timeoutId: ReturnType<typeof setTimeout>;
|
let timeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
|
|
||||||
interface ComponentError {
|
interface ComponentError {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
message: string;
|
message: string;
|
||||||
@ -13,29 +11,24 @@ interface ComponentError {
|
|||||||
componentStack: string | null | undefined;
|
componentStack: string | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function isErrorReportingAllowed(error?: Error): boolean {
|
function isErrorReportingAllowed(error?: Error): boolean {
|
||||||
// Если ошибка помечена как debug-override — всегда отправлять
|
// Если ошибка помечена как debug-override — всегда отправлять
|
||||||
if (error && (error as any).__forceSend) return true;
|
if (error && (error as any).__forceSend) return true;
|
||||||
|
|
||||||
// Проверяем домен
|
// Проверяем домен
|
||||||
const currentDomain = window.location.hostname;
|
const currentDomain = window.location.hostname;
|
||||||
|
|
||||||
return currentDomain !== 'localhost';
|
return currentDomain !== 'localhost';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleComponentError(error: Error, info: ErrorInfo, tickets: Ticket[]) {
|
// Новый API: getTickets — callback, возвращающий актуальные тикеты
|
||||||
|
export function handleComponentError(error: Error, info: ErrorInfo, getTickets: () => Ticket[]) {
|
||||||
//репортим только о авторизонышах
|
//репортим только о авторизонышах
|
||||||
if (!getAuthToken()) return;
|
if (!getAuthToken()) return;
|
||||||
|
|
||||||
// Проверяем разрешение на отправку ошибок (по домену)
|
// Проверяем разрешение на отправку ошибок (по домену)
|
||||||
if (!isErrorReportingAllowed(error)) {
|
if (!isErrorReportingAllowed(error)) {
|
||||||
console.log('❌ Отправка ошибки заблокирована:', error.message);
|
console.log('❌ Отправка ошибки заблокирована:', error.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`✅ Обработка ошибки: ${error.message}`);
|
console.log(`✅ Обработка ошибки: ${error.message}`);
|
||||||
|
|
||||||
// Копируем __forceSend если есть
|
// Копируем __forceSend если есть
|
||||||
const componentError: ComponentError & { __forceSend?: boolean } = {
|
const componentError: ComponentError & { __forceSend?: boolean } = {
|
||||||
timestamp: Math.floor(Date.now() / 1000),
|
timestamp: Math.floor(Date.now() / 1000),
|
||||||
@ -44,30 +37,21 @@ export function handleComponentError(error: Error, info: ErrorInfo, tickets: Tic
|
|||||||
componentStack: info.componentStack,
|
componentStack: info.componentStack,
|
||||||
...(error && (error as any).__forceSend ? { __forceSend: true } : {})
|
...(error && (error as any).__forceSend ? { __forceSend: true } : {})
|
||||||
};
|
};
|
||||||
|
queueErrorRequest(componentError, getTickets);
|
||||||
queueErrorRequest(componentError, tickets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Ставит ошибку в очередь для отправки
|
// Ставит ошибку в очередь для отправки, через 1 секунду вызывает sendErrorsToServer
|
||||||
//Через 1 секунду вызывает sendErrorsToServer
|
export function queueErrorRequest(error: ComponentError, getTickets: () => Ticket[]) {
|
||||||
export function queueErrorRequest(error: ComponentError, tickets: Ticket[]) {
|
|
||||||
errorsQueue.push(error);
|
errorsQueue.push(error);
|
||||||
|
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
sendErrorsToServer(tickets);
|
sendErrorsToServer(getTickets);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Отправляет накопленные ошибки в тикеты, ищет существующий тикет с system: true или создает новый
|
||||||
//Отправляет накопленные ошибки в тикеты
|
export async function sendErrorsToServer(getTickets: () => Ticket[]) {
|
||||||
//Ищет существующий тикет с system: true или создает новый
|
|
||||||
|
|
||||||
export async function sendErrorsToServer(
|
|
||||||
tickets: Ticket[]
|
|
||||||
) {
|
|
||||||
if (errorsQueue.length === 0) return;
|
if (errorsQueue.length === 0) return;
|
||||||
|
|
||||||
// Проверяем разрешение на отправку ошибок (по домену и debug-override)
|
// Проверяем разрешение на отправку ошибок (по домену и debug-override)
|
||||||
// Если хотя бы одна ошибка в очереди с __forceSend, отправляем всё
|
// Если хотя бы одна ошибка в очереди с __forceSend, отправляем всё
|
||||||
const forceSend = errorsQueue.some(e => (e as any).__forceSend);
|
const forceSend = errorsQueue.some(e => (e as any).__forceSend);
|
||||||
@ -76,16 +60,14 @@ export async function sendErrorsToServer(
|
|||||||
errorsQueue = [];
|
errorsQueue = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const tickets = getTickets();
|
||||||
try {
|
try {
|
||||||
// Формируем сообщение об ошибке
|
// Формируем сообщение об ошибке
|
||||||
const errorMessage = errorsQueue.map(error => {
|
const errorMessage = errorsQueue.map(error => {
|
||||||
return `[${new Date(error.timestamp * 1000).toISOString()}] ${error.message}\n\nCall Stack:\n${error.callStack || 'N/A'}\n\nComponent Stack:\n${error.componentStack || 'N/A'}`;
|
return `[${new Date(error.timestamp * 1000).toISOString()}] ${error.message}\n\nCall Stack:\n${error.callStack || 'N/A'}\n\nComponent Stack:\n${error.componentStack || 'N/A'}`;
|
||||||
}).join('\n\n---\n\n');
|
}).join('\n\n---\n\n');
|
||||||
|
|
||||||
// ВСЕГДА ищем тикет через API
|
// ВСЕГДА ищем тикет через API
|
||||||
const existingSystemTicket = await findSystemTicket(tickets);
|
const existingSystemTicket = await findSystemTicket(tickets);
|
||||||
|
|
||||||
if (existingSystemTicket) {
|
if (existingSystemTicket) {
|
||||||
sendTicketMessage({
|
sendTicketMessage({
|
||||||
ticketId: existingSystemTicket,
|
ticketId: existingSystemTicket,
|
||||||
@ -109,9 +91,7 @@ export async function sendErrorsToServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ищет существующий тикет с system: true
|
// Ищет существующий тикет с system: true
|
||||||
export async function findSystemTicket(
|
export async function findSystemTicket(tickets: Ticket[]) {
|
||||||
tickets: Ticket[]
|
|
||||||
) {
|
|
||||||
for (const ticket of tickets) {
|
for (const ticket of tickets) {
|
||||||
console.log("[findSystemTicket] Проверяем тикет:", ticket);
|
console.log("[findSystemTicket] Проверяем тикет:", ticket);
|
||||||
if (!('messages' in ticket)) {
|
if (!('messages' in ticket)) {
|
||||||
@ -119,7 +99,11 @@ export async function findSystemTicket(
|
|||||||
console.log("[findSystemTicket] Найден тикет по top_message.system:true:", ticket.id);
|
console.log("[findSystemTicket] Найден тикет по top_message.system:true:", ticket.id);
|
||||||
return ticket.id;
|
return ticket.id;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
export function clearErrorHandlingConfig () {
|
||||||
}
|
clearTimeout(timeoutId);
|
||||||
|
errorsQueue = [];
|
||||||
}
|
}
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@frontend/kitui",
|
"name": "@frontend/kitui",
|
||||||
"version": "1.0.108",
|
"version": "1.0.109",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@frontend/kitui",
|
"name": "@frontend/kitui",
|
||||||
"version": "1.0.108",
|
"version": "1.0.109",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"immer": "^10.0.2",
|
"immer": "^10.0.2",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@frontend/kitui",
|
"name": "@frontend/kitui",
|
||||||
"version": "1.0.109",
|
"version": "1.0.110",
|
||||||
"description": "test",
|
"description": "test",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
|
Loading…
Reference in New Issue
Block a user