Update package dependencies and enhance session management features
- Added react-hot-toast for improved user notifications in the application. - Updated baseline-browser-mapping to version 2.9.2. - Introduced maxInstances property in Session and App schemas to manage concurrent instances. - Refactored server session handling to enforce instance limits and improve error messaging. - Removed GPU memory management from server registration and session assignment logic for cleaner implementation. - Enhanced error handling in session management with localized messages for better user experience.
This commit is contained in:
Generated
+29
-5
@@ -16,6 +16,7 @@
|
||||
"motion": "^12.23.24",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-qr-code": "^2.0.18",
|
||||
"react-router": "^7.9.3",
|
||||
"socket.io-client": "^4.8.1",
|
||||
@@ -30,6 +31,7 @@
|
||||
"@types/uuid": "^11.0.0",
|
||||
"@vitejs/plugin-react-swc": "^4.1.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"baseline-browser-mapping": "^2.9.2",
|
||||
"eslint": "^9.36.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.22",
|
||||
@@ -1905,11 +1907,10 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.8.13",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.13.tgz",
|
||||
"integrity": "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==",
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.2.tgz",
|
||||
"integrity": "sha512-PxSsosKQjI38iXkmb3d0Y32efqyA0uW4s41u4IVBsLlWLhCiYNpH/AfNOVWRqCQBlD8TFJTz6OUWNd4DFJCnmw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"baseline-browser-mapping": "dist/cli.js"
|
||||
}
|
||||
@@ -2168,7 +2169,6 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
@@ -2810,6 +2810,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/goober": {
|
||||
"version": "2.1.18",
|
||||
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz",
|
||||
"integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==",
|
||||
"peerDependencies": {
|
||||
"csstype": "^3.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/graphemer": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
|
||||
@@ -3687,6 +3695,22 @@
|
||||
"react": "^19.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hot-toast": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz",
|
||||
"integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==",
|
||||
"dependencies": {
|
||||
"csstype": "^3.1.3",
|
||||
"goober": "^2.1.16"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16",
|
||||
"react-dom": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"@types/uuid": "^11.0.0",
|
||||
"@vitejs/plugin-react-swc": "^4.1.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"baseline-browser-mapping": "^2.9.2",
|
||||
"eslint": "^9.36.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.22",
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { HTTPError } from "ky";
|
||||
|
||||
/**
|
||||
* Извлекает сообщение об ошибке из ответа API
|
||||
* Elysia возвращает ошибки как строку в теле ответа или как JSON с полем message
|
||||
*/
|
||||
export async function extractErrorMessage(error: unknown): Promise<string> {
|
||||
// Если это HTTPError от ky
|
||||
if (error instanceof HTTPError) {
|
||||
try {
|
||||
// Сначала пытаемся получить текст ответа
|
||||
const responseText = await error.response.text();
|
||||
|
||||
// Пытаемся распарсить как JSON
|
||||
try {
|
||||
const errorData = JSON.parse(responseText);
|
||||
// Проверяем различные форматы ответа об ошибке
|
||||
return (
|
||||
errorData.message ||
|
||||
errorData.error ||
|
||||
responseText ||
|
||||
error.response.statusText ||
|
||||
`Ошибка ${error.response.status}`
|
||||
);
|
||||
} catch {
|
||||
// Если не JSON, значит это строка - используем её напрямую
|
||||
// Elysia возвращает ошибки как строку при использовании status(code, message)
|
||||
return responseText || error.response.statusText || `Ошибка ${error.response.status}`;
|
||||
}
|
||||
} catch {
|
||||
// Если не удалось получить текст ответа, используем статус код
|
||||
const statusMessages: Record<number, string> = {
|
||||
400: "Неверный запрос",
|
||||
401: "Требуется авторизация",
|
||||
403: "Доступ запрещен",
|
||||
404: "Ресурс не найден",
|
||||
409: "Конфликт данных",
|
||||
500: "Внутренняя ошибка сервера",
|
||||
503: "Сервис временно недоступен",
|
||||
};
|
||||
|
||||
return (
|
||||
statusMessages[error.response.status] ||
|
||||
error.response.statusText ||
|
||||
`Ошибка ${error.response.status}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Если это обычная Error
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
// Если это объект с полем message
|
||||
if (typeof error === "object" && error !== null && "message" in error) {
|
||||
return String((error as { message: unknown }).message);
|
||||
}
|
||||
|
||||
// Дефолтное сообщение
|
||||
return "Произошла неизвестная ошибка";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { api } from "../lib/api";
|
||||
import { useNavigate } from "react-router";
|
||||
import toast from "react-hot-toast";
|
||||
import { extractErrorMessage } from "../lib/errorUtils";
|
||||
|
||||
interface Session {
|
||||
id: string;
|
||||
@@ -44,9 +46,18 @@ function TestPage() {
|
||||
navigate(`/sessions/${response.session.id}`);
|
||||
} catch (err) {
|
||||
console.error("Failed to start session:", err);
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Не удалось запустить приложение"
|
||||
);
|
||||
|
||||
// Извлекаем сообщение об ошибке из ответа
|
||||
const errorMessage = await extractErrorMessage(err);
|
||||
|
||||
// Показываем ошибку через toast
|
||||
toast.error(errorMessage, {
|
||||
duration: 5000,
|
||||
position: "top-center",
|
||||
});
|
||||
|
||||
// Также сохраняем для отображения в UI (если нужно)
|
||||
setError(errorMessage);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface Session {
|
||||
title: string;
|
||||
gpuLimitMb: number | null;
|
||||
psVersion: number | null;
|
||||
maxInstances: number | null;
|
||||
};
|
||||
server?: {
|
||||
id: string;
|
||||
|
||||
Reference in New Issue
Block a user