Spaces:
Sleeping
Sleeping
update
Browse files- src/App.tsx +40 -13
- src/api/auth/authApi.ts +14 -0
- src/api/auth/hooks.ts +24 -0
- src/api/auth/types.ts +9 -0
- src/components/common/navbar/Navbar.tsx +55 -33
- src/components/pages/auth/Login.scss +73 -0
- src/components/pages/auth/Login.tsx +51 -0
- src/components/pages/llmConfigs/LlmConfigList.tsx +1 -1
- src/components/pages/llmConfigs/LlmConfigModal.tsx +1 -1
- src/context/AuthContext.tsx +63 -0
- src/index.scss +1 -1
- src/main.tsx +2 -2
- src/shared/api/query.ts +34 -59
- tsconfig.tsbuildinfo +1 -1
src/App.tsx
CHANGED
@@ -3,31 +3,58 @@ import { Routes, Route, BrowserRouter as Router, Navigate } from "react-router-d
|
|
3 |
import Navbar from '@/components/common/navbar/Navbar';
|
4 |
import Page from "@/components/pages/main/Page";
|
5 |
import Logs from "@/components/pages/logsPage/Logs";
|
6 |
-
import Vectorization from "
|
7 |
import { pdfjs } from "react-pdf";
|
8 |
-
import LLMConfigList from "
|
9 |
-
import LlmPromptList from "
|
|
|
|
|
10 |
|
11 |
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
12 |
"pdfjs-dist/build/pdf.worker.min.mjs",
|
13 |
import.meta.url
|
14 |
).toString();
|
15 |
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
return (
|
18 |
<Router>
|
19 |
-
<Navbar
|
|
|
20 |
<Routes>
|
21 |
-
|
22 |
-
<Route path="/logs" element={
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
<Route path="/
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
</Routes>
|
|
|
29 |
</Router>
|
30 |
);
|
31 |
}
|
32 |
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
import Navbar from '@/components/common/navbar/Navbar';
|
4 |
import Page from "@/components/pages/main/Page";
|
5 |
import Logs from "@/components/pages/logsPage/Logs";
|
6 |
+
import Vectorization from "@/components/pages/vectorizationPage/Vectorization";
|
7 |
import { pdfjs } from "react-pdf";
|
8 |
+
import LLMConfigList from "@/components/pages/llmConfigs/LlmConfigList";
|
9 |
+
import LlmPromptList from "@/components/pages/llmPrompts/LlmPromptList";
|
10 |
+
import LoginPage from "@/components/pages/auth/Login";
|
11 |
+
import { AuthProvider, useAuth } from "@/context/AuthContext";
|
12 |
|
13 |
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
14 |
"pdfjs-dist/build/pdf.worker.min.mjs",
|
15 |
import.meta.url
|
16 |
).toString();
|
17 |
|
18 |
+
const App: React.FC = () => {
|
19 |
+
const { isAuthenticated } = useAuth();
|
20 |
+
|
21 |
+
const PrivateRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
22 |
+
return isAuthenticated ? <>{children}</> : <Navigate to="/login" />;
|
23 |
+
};
|
24 |
+
|
25 |
return (
|
26 |
<Router>
|
27 |
+
<Navbar/>
|
28 |
+
<div className="app-content">
|
29 |
<Routes>
|
30 |
+
<Route path="/login" element={<LoginPage />} />
|
31 |
+
<Route path="/logs" element={
|
32 |
+
<PrivateRoute>
|
33 |
+
<Logs />
|
34 |
+
</PrivateRoute>} />
|
35 |
+
<Route path="/docs" element={
|
36 |
+
<PrivateRoute>
|
37 |
+
<Vectorization />
|
38 |
+
</PrivateRoute>} />
|
39 |
+
<Route path="/llmconfig" element={
|
40 |
+
<PrivateRoute>
|
41 |
+
<LLMConfigList />
|
42 |
+
</PrivateRoute>
|
43 |
+
} />
|
44 |
+
<Route path="/llmprompt" element={
|
45 |
+
<PrivateRoute>
|
46 |
+
<LlmPromptList />
|
47 |
+
</PrivateRoute>} />
|
48 |
</Routes>
|
49 |
+
</div>
|
50 |
</Router>
|
51 |
);
|
52 |
}
|
53 |
|
54 |
+
const RootApp: React.FC = () => (
|
55 |
+
<AuthProvider>
|
56 |
+
<App />
|
57 |
+
</AuthProvider>
|
58 |
+
);
|
59 |
+
|
60 |
+
export default RootApp;
|
src/api/auth/authApi.ts
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { query } from '@/shared/api/query';
|
2 |
+
import { AuthResponse, LoginRequest } from './types';
|
3 |
+
|
4 |
+
export const login = async (data: LoginRequest): Promise<AuthResponse> => {
|
5 |
+
const response = await query<AuthResponse>({
|
6 |
+
url: '/auth/login',
|
7 |
+
method: 'post',
|
8 |
+
data,
|
9 |
+
});
|
10 |
+
if ('error' in response) {
|
11 |
+
throw new Error(`Ошибка авторизации: ${response.error.status}`);
|
12 |
+
}
|
13 |
+
return response.data;
|
14 |
+
};
|
src/api/auth/hooks.ts
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useState, useEffect } from 'react';
|
2 |
+
import { useMutation } from '@tanstack/react-query';
|
3 |
+
import { login } from './authApi';
|
4 |
+
import { LoginRequest } from './types';
|
5 |
+
|
6 |
+
export const useAuth = () => {
|
7 |
+
|
8 |
+
const loginMutation = useMutation({
|
9 |
+
mutationFn: (data: LoginRequest) => login(data),
|
10 |
+
onSuccess: (data) => {
|
11 |
+
console.log(data)
|
12 |
+
return data;
|
13 |
+
},
|
14 |
+
onError: (error) => {
|
15 |
+
console.error('Login Error:', error);
|
16 |
+
},
|
17 |
+
});
|
18 |
+
|
19 |
+
return {
|
20 |
+
login: loginMutation.mutateAsync,
|
21 |
+
isLoading: loginMutation.isPending,
|
22 |
+
error: loginMutation.error,
|
23 |
+
};
|
24 |
+
};
|
src/api/auth/types.ts
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export interface LoginRequest {
|
2 |
+
username: string;
|
3 |
+
password: string;
|
4 |
+
}
|
5 |
+
|
6 |
+
export interface AuthResponse {
|
7 |
+
access_token: string;
|
8 |
+
token_type: string;
|
9 |
+
}
|
src/components/common/navbar/Navbar.tsx
CHANGED
@@ -1,43 +1,65 @@
|
|
1 |
import React from 'react';
|
2 |
-
import { NavLink } from 'react-router-dom';
|
3 |
import './Navbar.scss';
|
|
|
4 |
|
5 |
const Navbar: React.FC = () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
return (
|
7 |
<nav className="navbar">
|
8 |
<ul>
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
</ul>
|
42 |
</nav>
|
43 |
);
|
|
|
1 |
import React from 'react';
|
2 |
+
import { NavLink, useNavigate } from 'react-router-dom';
|
3 |
import './Navbar.scss';
|
4 |
+
import { useAuth } from '@/context/AuthContext';
|
5 |
|
6 |
const Navbar: React.FC = () => {
|
7 |
+
const { isAuthenticated, logout } = useAuth();
|
8 |
+
const navigate = useNavigate();
|
9 |
+
|
10 |
+
const handleLogout = () => {
|
11 |
+
logout();
|
12 |
+
navigate('/login');
|
13 |
+
};
|
14 |
+
|
15 |
return (
|
16 |
<nav className="navbar">
|
17 |
<ul>
|
18 |
+
{isAuthenticated ? (
|
19 |
+
<>
|
20 |
+
<li>
|
21 |
+
<NavLink
|
22 |
+
to="/logs"
|
23 |
+
className={({ isActive }) => (isActive ? 'active' : '')}
|
24 |
+
>
|
25 |
+
Логи
|
26 |
+
</NavLink>
|
27 |
+
</li>
|
28 |
+
<li>
|
29 |
+
<NavLink
|
30 |
+
to="/docs"
|
31 |
+
className={({ isActive }) => (isActive ? 'active' : '')}
|
32 |
+
>
|
33 |
+
Датасеты
|
34 |
+
</NavLink>
|
35 |
+
</li>
|
36 |
+
<li>
|
37 |
+
<NavLink
|
38 |
+
to="/llmconfig"
|
39 |
+
className={({ isActive }) => (isActive ? 'active' : '')}
|
40 |
+
>
|
41 |
+
Настройки LLM
|
42 |
+
</NavLink>
|
43 |
+
</li>
|
44 |
+
<li>
|
45 |
+
<NavLink
|
46 |
+
to="/llmprompt"
|
47 |
+
className={({ isActive }) => (isActive ? 'active' : '')}
|
48 |
+
>
|
49 |
+
Системные промпты
|
50 |
+
</NavLink>
|
51 |
+
</li>
|
52 |
+
<li>
|
53 |
+
<button onClick={handleLogout}>Выход</button>
|
54 |
+
</li>
|
55 |
+
</>
|
56 |
+
) : (
|
57 |
+
<li>
|
58 |
+
<NavLink to="/login" className={({ isActive }) => (isActive ? 'active' : '')}>
|
59 |
+
Вход
|
60 |
+
</NavLink>
|
61 |
+
</li>
|
62 |
+
)}
|
63 |
</ul>
|
64 |
</nav>
|
65 |
);
|
src/components/pages/auth/Login.scss
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.login-page {
|
2 |
+
display: flex;
|
3 |
+
flex-direction: column;
|
4 |
+
align-items: center;
|
5 |
+
justify-content: center;
|
6 |
+
height: 100vh;
|
7 |
+
background-color: #f5f5f5;
|
8 |
+
|
9 |
+
h2 {
|
10 |
+
margin-bottom: 20px;
|
11 |
+
font-size: 24px;
|
12 |
+
color: #333;
|
13 |
+
}
|
14 |
+
|
15 |
+
form {
|
16 |
+
display: flex;
|
17 |
+
flex-direction: column;
|
18 |
+
gap: 15px;
|
19 |
+
width: 300px;
|
20 |
+
padding: 20px;
|
21 |
+
background-color: white;
|
22 |
+
border-radius: 8px;
|
23 |
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
24 |
+
|
25 |
+
div {
|
26 |
+
display: flex;
|
27 |
+
flex-direction: column;
|
28 |
+
|
29 |
+
label {
|
30 |
+
margin-bottom: 5px;
|
31 |
+
font-size: 14px;
|
32 |
+
color: #555;
|
33 |
+
}
|
34 |
+
|
35 |
+
input {
|
36 |
+
padding: 8px;
|
37 |
+
font-size: 16px;
|
38 |
+
border: 1px solid #ddd;
|
39 |
+
border-radius: 4px;
|
40 |
+
outline: none;
|
41 |
+
|
42 |
+
&:focus {
|
43 |
+
border-color: #28a745;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
.error {
|
49 |
+
color: #dc3545;
|
50 |
+
font-size: 14px;
|
51 |
+
text-align: center;
|
52 |
+
}
|
53 |
+
|
54 |
+
button {
|
55 |
+
padding: 10px;
|
56 |
+
font-size: 16px;
|
57 |
+
background-color: #28a745;
|
58 |
+
color: white;
|
59 |
+
border: none;
|
60 |
+
border-radius: 4px;
|
61 |
+
cursor: pointer;
|
62 |
+
|
63 |
+
&:hover {
|
64 |
+
background-color: #218838;
|
65 |
+
}
|
66 |
+
|
67 |
+
&:disabled {
|
68 |
+
background-color: #6c757d;
|
69 |
+
cursor: not-allowed;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
src/components/pages/auth/Login.tsx
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useState } from 'react';
|
2 |
+
import { useNavigate } from 'react-router-dom';
|
3 |
+
import './Login.scss';
|
4 |
+
import { useAuth } from '@/context/AuthContext';
|
5 |
+
|
6 |
+
const LoginPage: React.FC = () => {
|
7 |
+
const [username, setUsername] = useState('');
|
8 |
+
const [password, setPassword] = useState('');
|
9 |
+
const { login, isLoading, error } = useAuth();
|
10 |
+
const navigate = useNavigate();
|
11 |
+
|
12 |
+
const handleSubmit = async (e: React.FormEvent) => {
|
13 |
+
e.preventDefault();
|
14 |
+
try {
|
15 |
+
await login({ username, password });
|
16 |
+
navigate('/logs', { replace: true });
|
17 |
+
} catch {
|
18 |
+
// Ошибка уже логируется в хуке
|
19 |
+
}
|
20 |
+
};
|
21 |
+
|
22 |
+
return (
|
23 |
+
<div className="login-page">
|
24 |
+
<h2>Вход в админку</h2>
|
25 |
+
<form onSubmit={handleSubmit}>
|
26 |
+
<div>
|
27 |
+
<label>Логин:</label>
|
28 |
+
<input
|
29 |
+
type="text"
|
30 |
+
value={username}
|
31 |
+
onChange={(e) => setUsername(e.target.value)}
|
32 |
+
/>
|
33 |
+
</div>
|
34 |
+
<div>
|
35 |
+
<label>Пароль:</label>
|
36 |
+
<input
|
37 |
+
type="password"
|
38 |
+
value={password}
|
39 |
+
onChange={(e) => setPassword(e.target.value)}
|
40 |
+
/>
|
41 |
+
</div>
|
42 |
+
{error && <p className="error">Неверный логин или пароль</p>}
|
43 |
+
<button type="submit" disabled={isLoading}>
|
44 |
+
{isLoading ? 'Вход...' : 'Войти'}
|
45 |
+
</button>
|
46 |
+
</form>
|
47 |
+
</div>
|
48 |
+
);
|
49 |
+
};
|
50 |
+
|
51 |
+
export default LoginPage;
|
src/components/pages/llmConfigs/LlmConfigList.tsx
CHANGED
@@ -4,7 +4,7 @@ import { GoTrash, GoStar, GoStarFill } from 'react-icons/go';
|
|
4 |
import { useQuery } from '@tanstack/react-query';
|
5 |
import { useLLMConfigs, } from "@/api/llmConfigs/hooks";
|
6 |
import { LLMConfig } from "@/api/llmConfigs/types";
|
7 |
-
import './
|
8 |
import LLMConfigModal from './LlmConfigModal';
|
9 |
import { fetchDefaultLLMConfig } from '@/api/llmConfigs/llmConfigApi';
|
10 |
|
|
|
4 |
import { useQuery } from '@tanstack/react-query';
|
5 |
import { useLLMConfigs, } from "@/api/llmConfigs/hooks";
|
6 |
import { LLMConfig } from "@/api/llmConfigs/types";
|
7 |
+
import './LLMConfigList.scss';
|
8 |
import LLMConfigModal from './LlmConfigModal';
|
9 |
import { fetchDefaultLLMConfig } from '@/api/llmConfigs/llmConfigApi';
|
10 |
|
src/components/pages/llmConfigs/LlmConfigModal.tsx
CHANGED
@@ -4,7 +4,7 @@ import { GoX } from 'react-icons/go';
|
|
4 |
import { LLMConfig } from '@/api/llmConfigs/types';
|
5 |
import { useQuery } from '@tanstack/react-query';
|
6 |
import { fetchLLMConfigById, fetchDefaultLLMConfig } from '@/api/llmConfigs/llmConfigApi';
|
7 |
-
import './
|
8 |
|
9 |
interface LLMConfigModalProps {
|
10 |
isOpen: boolean;
|
|
|
4 |
import { LLMConfig } from '@/api/llmConfigs/types';
|
5 |
import { useQuery } from '@tanstack/react-query';
|
6 |
import { fetchLLMConfigById, fetchDefaultLLMConfig } from '@/api/llmConfigs/llmConfigApi';
|
7 |
+
import './LLMConfigModal.scss';
|
8 |
|
9 |
interface LLMConfigModalProps {
|
10 |
isOpen: boolean;
|
src/context/AuthContext.tsx
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
2 |
+
import { useMutation } from '@tanstack/react-query';
|
3 |
+
import { login } from '@/api/auth/authApi';
|
4 |
+
import { LoginRequest } from '@/api/auth/types';
|
5 |
+
|
6 |
+
interface AuthContextType {
|
7 |
+
isAuthenticated: boolean;
|
8 |
+
login: (data: LoginRequest) => Promise<void>;
|
9 |
+
logout: () => void;
|
10 |
+
isLoading: boolean;
|
11 |
+
error: Error | null;
|
12 |
+
}
|
13 |
+
|
14 |
+
const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
15 |
+
|
16 |
+
export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
17 |
+
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(() => {
|
18 |
+
// Инициализируем состояние сразу из localStorage
|
19 |
+
return !!localStorage.getItem('authToken');
|
20 |
+
});
|
21 |
+
|
22 |
+
const loginMutation = useMutation({
|
23 |
+
mutationFn: (data: LoginRequest) => login(data),
|
24 |
+
onSuccess: (data) => {
|
25 |
+
localStorage.setItem('authToken', data.access_token);
|
26 |
+
setIsAuthenticated(true);
|
27 |
+
},
|
28 |
+
onError: (error) => {
|
29 |
+
console.error('Login Error:', error);
|
30 |
+
},
|
31 |
+
});
|
32 |
+
|
33 |
+
const loginHandler = async (data: LoginRequest) => {
|
34 |
+
await loginMutation.mutateAsync(data);
|
35 |
+
};
|
36 |
+
|
37 |
+
const logout = () => {
|
38 |
+
localStorage.removeItem('authToken');
|
39 |
+
setIsAuthenticated(false);
|
40 |
+
};
|
41 |
+
|
42 |
+
return (
|
43 |
+
<AuthContext.Provider
|
44 |
+
value={{
|
45 |
+
isAuthenticated,
|
46 |
+
login: loginHandler,
|
47 |
+
logout,
|
48 |
+
isLoading: loginMutation.isPending,
|
49 |
+
error: loginMutation.error,
|
50 |
+
}}
|
51 |
+
>
|
52 |
+
{children}
|
53 |
+
</AuthContext.Provider>
|
54 |
+
);
|
55 |
+
};
|
56 |
+
|
57 |
+
export const useAuth = () => {
|
58 |
+
const context = useContext(AuthContext);
|
59 |
+
if (!context) {
|
60 |
+
throw new Error('useAuth must be used within an AuthProvider');
|
61 |
+
}
|
62 |
+
return context;
|
63 |
+
};
|
src/index.scss
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
@
|
2 |
|
3 |
:root {
|
4 |
--font-body: Arial, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans",
|
|
|
1 |
+
@use "@fontsource/fira-mono";
|
2 |
|
3 |
:root {
|
4 |
--font-body: Arial, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans",
|
src/main.tsx
CHANGED
@@ -3,7 +3,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
3 |
import { Provider } from "react-redux";
|
4 |
import { store } from "./store/index.js";
|
5 |
import Modal from 'react-modal';
|
6 |
-
import
|
7 |
import "./index.scss";
|
8 |
|
9 |
export const queryClient = new QueryClient();
|
@@ -11,7 +11,7 @@ export const queryClient = new QueryClient();
|
|
11 |
createRoot(document.getElementById("root")!).render(
|
12 |
<QueryClientProvider client={queryClient}>
|
13 |
<Provider store={store}>
|
14 |
-
<
|
15 |
</Provider>
|
16 |
</QueryClientProvider>
|
17 |
);
|
|
|
3 |
import { Provider } from "react-redux";
|
4 |
import { store } from "./store/index.js";
|
5 |
import Modal from 'react-modal';
|
6 |
+
import RootApp from "./App";
|
7 |
import "./index.scss";
|
8 |
|
9 |
export const queryClient = new QueryClient();
|
|
|
11 |
createRoot(document.getElementById("root")!).render(
|
12 |
<QueryClientProvider client={queryClient}>
|
13 |
<Provider store={store}>
|
14 |
+
<RootApp />
|
15 |
</Provider>
|
16 |
</QueryClientProvider>
|
17 |
);
|
src/shared/api/query.ts
CHANGED
@@ -1,23 +1,14 @@
|
|
1 |
-
import axios, {
|
2 |
-
|
3 |
-
|
4 |
-
AxiosResponse,
|
5 |
-
AxiosResponseHeaders,
|
6 |
-
InternalAxiosRequestConfig,
|
7 |
-
RawAxiosResponseHeaders,
|
8 |
-
ResponseType,
|
9 |
-
} from "axios";
|
10 |
-
|
11 |
-
import { apiBaseUrl } from "../constants";
|
12 |
-
import { queryClient } from "@/main";
|
13 |
|
14 |
export interface IAxiosParams {
|
15 |
-
method: AxiosRequestConfig[
|
16 |
url: string;
|
17 |
-
params?: AxiosRequestConfig[
|
18 |
-
data?: AxiosRequestConfig[
|
19 |
-
headers?: AxiosRequestConfig[
|
20 |
-
responseType?:
|
21 |
notCauseError?: boolean;
|
22 |
signal?: AbortSignal;
|
23 |
}
|
@@ -26,50 +17,47 @@ export interface IQueryErrorResponse {
|
|
26 |
error: {
|
27 |
status: unknown;
|
28 |
data: unknown;
|
29 |
-
headers?:
|
30 |
notCauseError?: boolean;
|
31 |
};
|
32 |
}
|
33 |
|
34 |
export interface GenericIdentityFn<Type> {
|
35 |
data: Type;
|
36 |
-
headers?:
|
37 |
}
|
38 |
|
39 |
-
/**
|
40 |
-
* Инстанс аксиоса
|
41 |
-
*/
|
42 |
export const instance = axios.create({
|
43 |
-
baseURL: apiBaseUrl ? `${apiBaseUrl}` :
|
44 |
timeout: 600000,
|
45 |
});
|
46 |
|
47 |
-
/**
|
48 |
-
* Интерцептор на запрос
|
49 |
-
*/
|
50 |
const requestInterceptors = (req: InternalAxiosRequestConfig) => {
|
|
|
|
|
|
|
|
|
|
|
51 |
return req;
|
52 |
};
|
53 |
|
54 |
-
/**
|
55 |
-
* Интерцептор на успешный ответ сервера
|
56 |
-
*/
|
57 |
const successInterceptors = (response: AxiosResponse) => response;
|
58 |
|
59 |
-
/**
|
60 |
-
* Интерцептор на ошибку сервера
|
61 |
-
*/
|
62 |
const errorInterceptors = async (error: AxiosError) => {
|
63 |
const message = error.message;
|
64 |
-
if (!axios.isCancel(error) && !message.includes("409")) {
|
65 |
-
alert(`${message} Произошла ошибка`);
|
66 |
-
}
|
67 |
|
68 |
-
if (message.includes(
|
69 |
-
console.log(
|
70 |
-
queryClient.invalidateQueries({ queryKey: [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
}
|
72 |
-
|
73 |
return Promise.reject(error);
|
74 |
};
|
75 |
|
@@ -84,38 +72,25 @@ export const query = async <T>(
|
|
84 |
const requestSignal = signal || controller.signal;
|
85 |
|
86 |
try {
|
87 |
-
console.log(
|
88 |
const result = await instance({
|
89 |
url: `${baseUrl}${url}`,
|
90 |
signal: requestSignal,
|
91 |
...requestOptions,
|
92 |
});
|
93 |
-
console.log(
|
94 |
return { data: result.data as T, headers: result.headers };
|
95 |
} catch (axiosError) {
|
96 |
if (axios.isCancel(axiosError)) {
|
97 |
-
console.log(
|
98 |
-
return {
|
99 |
-
error: {
|
100 |
-
status: "Cancelled",
|
101 |
-
data: "Request was cancelled",
|
102 |
-
notCauseError: true,
|
103 |
-
},
|
104 |
-
};
|
105 |
}
|
106 |
const err = axiosError as AxiosError;
|
107 |
-
console.log(
|
108 |
-
|
109 |
-
return {
|
110 |
-
error: {
|
111 |
-
status: err.response?.status,
|
112 |
-
data: err.response?.data,
|
113 |
-
headers: err.response?.headers,
|
114 |
-
},
|
115 |
-
};
|
116 |
} finally {
|
117 |
if (!signal) {
|
118 |
controller.abort();
|
119 |
}
|
120 |
}
|
121 |
-
};
|
|
|
1 |
+
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
2 |
+
import { apiBaseUrl } from '../constants';
|
3 |
+
import { queryClient } from '@/main';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
export interface IAxiosParams {
|
6 |
+
method: AxiosRequestConfig['method'];
|
7 |
url: string;
|
8 |
+
params?: AxiosRequestConfig['params'];
|
9 |
+
data?: AxiosRequestConfig['data'];
|
10 |
+
headers?: AxiosRequestConfig['headers'];
|
11 |
+
responseType?: AxiosRequestConfig['responseType'];
|
12 |
notCauseError?: boolean;
|
13 |
signal?: AbortSignal;
|
14 |
}
|
|
|
17 |
error: {
|
18 |
status: unknown;
|
19 |
data: unknown;
|
20 |
+
headers?: AxiosResponse['headers'];
|
21 |
notCauseError?: boolean;
|
22 |
};
|
23 |
}
|
24 |
|
25 |
export interface GenericIdentityFn<Type> {
|
26 |
data: Type;
|
27 |
+
headers?: AxiosResponse['headers'];
|
28 |
}
|
29 |
|
|
|
|
|
|
|
30 |
export const instance = axios.create({
|
31 |
+
baseURL: apiBaseUrl ? `${apiBaseUrl}` : '',
|
32 |
timeout: 600000,
|
33 |
});
|
34 |
|
|
|
|
|
|
|
35 |
const requestInterceptors = (req: InternalAxiosRequestConfig) => {
|
36 |
+
// Добавляем jwt токен для всех маршрутов
|
37 |
+
const token = localStorage.getItem('authToken');
|
38 |
+
if (token) {
|
39 |
+
req.headers.Authorization = `Bearer ${token}`;
|
40 |
+
}
|
41 |
return req;
|
42 |
};
|
43 |
|
|
|
|
|
|
|
44 |
const successInterceptors = (response: AxiosResponse) => response;
|
45 |
|
|
|
|
|
|
|
46 |
const errorInterceptors = async (error: AxiosError) => {
|
47 |
const message = error.message;
|
|
|
|
|
|
|
48 |
|
49 |
+
if (message.includes('409')) {
|
50 |
+
console.log('409');
|
51 |
+
queryClient.invalidateQueries({ queryKey: ['processing'] });
|
52 |
+
}
|
53 |
+
if (error.response?.status === 401) {
|
54 |
+
localStorage.removeItem('authToken');
|
55 |
+
window.location.href = '/login'; // Редирект на логин при 401
|
56 |
+
} else {
|
57 |
+
if (!axios.isCancel(error) && !message.includes('409')) {
|
58 |
+
alert(`${message} Произошла ошибка`);
|
59 |
+
}
|
60 |
}
|
|
|
61 |
return Promise.reject(error);
|
62 |
};
|
63 |
|
|
|
72 |
const requestSignal = signal || controller.signal;
|
73 |
|
74 |
try {
|
75 |
+
console.log('Попытка отправки запроса');
|
76 |
const result = await instance({
|
77 |
url: `${baseUrl}${url}`,
|
78 |
signal: requestSignal,
|
79 |
...requestOptions,
|
80 |
});
|
81 |
+
console.log('Запрос отправлен, результат:', result);
|
82 |
return { data: result.data as T, headers: result.headers };
|
83 |
} catch (axiosError) {
|
84 |
if (axios.isCancel(axiosError)) {
|
85 |
+
console.log('Запрос отменен');
|
86 |
+
return { error: { status: 'Cancelled', data: 'Request was cancelled', notCauseError: true } };
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
const err = axiosError as AxiosError;
|
89 |
+
console.log('Ошибка при отправке запроса');
|
90 |
+
return { error: { status: err.response?.status, data: err.response?.data, headers: err.response?.headers } };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
} finally {
|
92 |
if (!signal) {
|
93 |
controller.abort();
|
94 |
}
|
95 |
}
|
96 |
+
};
|
tsconfig.tsbuildinfo
CHANGED
@@ -1 +1 @@
|
|
1 |
-
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/documents/documentsapi.ts","./src/api/documents/hooks.ts","./src/api/documents/types.ts","./src/api/predictions/hooks.ts","./src/api/predictions/predictionsapi.ts","./src/api/predictions/types.ts","./src/components/generics/button/button.interface.ts","./src/components/generics/button/button.tsx","./src/components/generics/collapse/collapse.inreface.ts","./src/components/generics/collapse/collapse.tsx","./src/components/generics/dropdown/dropdown.interface.ts","./src/components/generics/dropdown/dropdown.tsx","./src/components/generics/editable/editable.interface.ts","./src/components/generics/editable/editable.tsx","./src/components/generics/input/input.interface.ts","./src/components/generics/input/input.tsx","./src/components/generics/loading/loading.tsx","./src/components/generics/modal/modal.interface.ts","./src/components/generics/modal/modal.tsx","./src/components/generics/sizechanger/sizechanger.tsx","./src/components/generics/sizechanger/sizechangerprops.ts","./src/components/generics/spinner/spinner.tsx","./src/components/generics/tag/tag.interface.ts","./src/components/generics/tag/tag.tsx","./src/components/generics/textarea/textarea.interface.ts","./src/components/generics/textarea/textarea.tsx","./src/components/generics/toggle/toggle.interface.ts","./src/components/generics/toggle/toggle.tsx","./src/components/generics/tooltip/tooltip.interface.ts","./src/components/generics/tooltip/tooltip.tsx","./src/components/pages/documentspage/documents.tsx","./src/components/pages/logspage/logs.tsx","./src/components/pages/main/page.tsx","./src/components/pages/vectorizationpage/vectorization.tsx","./src/components/views/abbreviationblock/abbreviationblock.interface.ts","./src/components/views/abbreviationblock/abbreviationsblock.tsx","./src/components/views/comment/comment.tsx","./src/components/views/comment/commentprops.ts","./src/components/views/documents/adddocuimentform/adddocumentform.interface.ts","./src/components/views/documents/adddocuimentform/adddocumentform.tsx","./src/components/views/documents/createdatasetform/createdatasetform.interface.ts","./src/components/views/documents/createdatasetform/createdatasetform.tsx","./src/components/views/documents/docslist/docslist.interface.ts","./src/components/views/documents/docslist/docslist.tsx","./src/components/views/llmanswer/llmanswer.tsx","./src/components/views/llmanswer/llmanswerprops.ts","./src/components/views/loginform/loginform.tsx","./src/components/views/pagination/pagination.tsx","./src/components/views/requesttextarea/requesttextarea.tsx","./src/components/views/requesttextarea/requesttextareaprops.ts","./src/components/views/search/documentmodal/documentmodal.tsx","./src/components/views/search/documentmodal/pdfviewer.tsx","./src/components/views/search/groupresults/groupresults.tsx","./src/components/views/search/groupresults/groupresultsprops.ts","./src/components/views/search/rocksnnresults/rocksnnresults.tsx","./src/components/views/search/rocksnnresults/rocksnnresultsprops.ts","./src/components/views/search/searchresults/searchresults.tsx","./src/components/views/search/searchresults/searchresultsprops.ts","./src/components/views/search/searchresultsitem/searchresultsitem.tsx","./src/components/views/search/searchresultsitem/searchresultsitemprops.ts","./src/components/views/search/segmentationresults/segmentationresult.tsx","./src/components/views/search/segmentationresults/segmentationsearch.ts","./src/components/views/search/staffresultsitem/staffresultsitem.tsx","./src/components/views/search/staffresultsitem/staffresultsitemprops.ts","./src/shared/constants.ts","./src/shared/types.ts","./src/shared/api/query.ts","./src/shared/hooks/useabbreviations/reducer.ts","./src/shared/hooks/useabbreviations/types.ts","./src/shared/hooks/useabbreviations/useabbreviation.ts","./src/shared/hooks/useauth/reducer.ts","./src/shared/hooks/useauth/types.ts","./src/shared/hooks/useauth/useauth.ts","./src/shared/utils/customparse.ts","./src/shared/utils/downloadexcel.ts","./src/shared/utils/downloadfile.ts","./src/shared/utils/escaperegexp.ts","./src/shared/utils/gettimezoneoffset.ts","./src/shared/utils/highlightmatches.ts","./src/shared/utils/parsedocumnetsinllmanswer.ts","./src/store/hooks.ts","./src/store/index.ts","./src/store/types.ts"],"version":"5.7.3"}
|
|
|
1 |
+
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/auth/authapi.ts","./src/api/auth/hooks.ts","./src/api/auth/types.ts","./src/api/documents/documentsapi.ts","./src/api/documents/hooks.ts","./src/api/documents/types.ts","./src/api/llmconfigs/hooks.ts","./src/api/llmconfigs/llmconfigapi.ts","./src/api/llmconfigs/types.ts","./src/api/llmprompts/hooks.ts","./src/api/llmprompts/llmpromptapi.ts","./src/api/llmprompts/types.ts","./src/api/predictions/hooks.ts","./src/api/predictions/predictionsapi.ts","./src/api/predictions/types.ts","./src/components/common/navbar/navbar.tsx","./src/components/generics/button/button.interface.ts","./src/components/generics/button/button.tsx","./src/components/generics/collapse/collapse.inreface.ts","./src/components/generics/collapse/collapse.tsx","./src/components/generics/dropdown/dropdown.interface.ts","./src/components/generics/dropdown/dropdown.tsx","./src/components/generics/editable/editable.interface.ts","./src/components/generics/editable/editable.tsx","./src/components/generics/input/input.interface.ts","./src/components/generics/input/input.tsx","./src/components/generics/loading/loading.tsx","./src/components/generics/modal/modal.interface.ts","./src/components/generics/modal/modal.tsx","./src/components/generics/sizechanger/sizechanger.tsx","./src/components/generics/sizechanger/sizechangerprops.ts","./src/components/generics/spinner/spinner.tsx","./src/components/generics/tag/tag.interface.ts","./src/components/generics/tag/tag.tsx","./src/components/generics/textarea/textarea.interface.ts","./src/components/generics/textarea/textarea.tsx","./src/components/generics/toggle/toggle.interface.ts","./src/components/generics/toggle/toggle.tsx","./src/components/generics/tooltip/tooltip.interface.ts","./src/components/generics/tooltip/tooltip.tsx","./src/components/pages/auth/login.tsx","./src/components/pages/documentspage/documents.tsx","./src/components/pages/llmconfigs/llmconfiglist.tsx","./src/components/pages/llmconfigs/llmconfigmodal.tsx","./src/components/pages/llmprompts/llmpromptlist.tsx","./src/components/pages/llmprompts/llmpromptmodal.tsx","./src/components/pages/logspage/logs.tsx","./src/components/pages/main/page.tsx","./src/components/pages/vectorizationpage/vectorization.tsx","./src/components/views/abbreviationblock/abbreviationblock.interface.ts","./src/components/views/abbreviationblock/abbreviationsblock.tsx","./src/components/views/comment/comment.tsx","./src/components/views/comment/commentprops.ts","./src/components/views/documents/adddocuimentform/adddocumentform.interface.ts","./src/components/views/documents/adddocuimentform/adddocumentform.tsx","./src/components/views/documents/createdatasetform/createdatasetform.interface.ts","./src/components/views/documents/createdatasetform/createdatasetform.tsx","./src/components/views/documents/docslist/docslist.interface.ts","./src/components/views/documents/docslist/docslist.tsx","./src/components/views/llmanswer/llmanswer.tsx","./src/components/views/llmanswer/llmanswerprops.ts","./src/components/views/loginform/loginform.tsx","./src/components/views/pagination/pagination.tsx","./src/components/views/requesttextarea/requesttextarea.tsx","./src/components/views/requesttextarea/requesttextareaprops.ts","./src/components/views/search/documentmodal/documentmodal.tsx","./src/components/views/search/documentmodal/pdfviewer.tsx","./src/components/views/search/groupresults/groupresults.tsx","./src/components/views/search/groupresults/groupresultsprops.ts","./src/components/views/search/rocksnnresults/rocksnnresults.tsx","./src/components/views/search/rocksnnresults/rocksnnresultsprops.ts","./src/components/views/search/searchresults/searchresults.tsx","./src/components/views/search/searchresults/searchresultsprops.ts","./src/components/views/search/searchresultsitem/searchresultsitem.tsx","./src/components/views/search/searchresultsitem/searchresultsitemprops.ts","./src/components/views/search/segmentationresults/segmentationresult.tsx","./src/components/views/search/segmentationresults/segmentationsearch.ts","./src/components/views/search/staffresultsitem/staffresultsitem.tsx","./src/components/views/search/staffresultsitem/staffresultsitemprops.ts","./src/context/authcontext.tsx","./src/shared/constants.ts","./src/shared/types.ts","./src/shared/api/query.ts","./src/shared/hooks/useabbreviations/reducer.ts","./src/shared/hooks/useabbreviations/types.ts","./src/shared/hooks/useabbreviations/useabbreviation.ts","./src/shared/hooks/useauth/reducer.ts","./src/shared/hooks/useauth/types.ts","./src/shared/hooks/useauth/useauth.ts","./src/shared/utils/customparse.ts","./src/shared/utils/downloadexcel.ts","./src/shared/utils/downloadfile.ts","./src/shared/utils/escaperegexp.ts","./src/shared/utils/gettimezoneoffset.ts","./src/shared/utils/highlightmatches.ts","./src/shared/utils/parsedocumnetsinllmanswer.ts","./src/store/hooks.ts","./src/store/index.ts","./src/store/types.ts"],"version":"5.7.3"}
|