modified: backend/src/types/index.ts
modified: frontend/src/App.tsx deleted: frontend/src/components/EndpointModal.tsx new file: frontend/src/pages/EndpointEditor.tsx modified: frontend/src/pages/Endpoints.tsx modified: frontend/src/pages/Folders.tsx modified: frontend/src/types/index.ts
This commit is contained in:
@@ -81,6 +81,7 @@ export interface EndpointParameter {
|
|||||||
required: boolean;
|
required: boolean;
|
||||||
default_value?: any;
|
default_value?: any;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
example_value?: string;
|
||||||
in: 'query' | 'body' | 'path';
|
in: 'query' | 'body' | 'path';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import Sidebar from '@/components/Sidebar';
|
|||||||
import Login from '@/pages/Login';
|
import Login from '@/pages/Login';
|
||||||
import Dashboard from '@/pages/Dashboard';
|
import Dashboard from '@/pages/Dashboard';
|
||||||
import Endpoints from '@/pages/Endpoints';
|
import Endpoints from '@/pages/Endpoints';
|
||||||
|
import EndpointEditor from '@/pages/EndpointEditor';
|
||||||
import ApiKeys from '@/pages/ApiKeys';
|
import ApiKeys from '@/pages/ApiKeys';
|
||||||
import Folders from '@/pages/Folders';
|
import Folders from '@/pages/Folders';
|
||||||
import Logs from '@/pages/Logs';
|
import Logs from '@/pages/Logs';
|
||||||
@@ -97,6 +98,26 @@ function App() {
|
|||||||
</PrivateRoute>
|
</PrivateRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/endpoints/new"
|
||||||
|
element={
|
||||||
|
<PrivateRoute>
|
||||||
|
<Layout>
|
||||||
|
<EndpointEditor />
|
||||||
|
</Layout>
|
||||||
|
</PrivateRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/endpoints/:id"
|
||||||
|
element={
|
||||||
|
<PrivateRoute>
|
||||||
|
<Layout>
|
||||||
|
<EndpointEditor />
|
||||||
|
</Layout>
|
||||||
|
</PrivateRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/endpoints"
|
path="/endpoints"
|
||||||
element={
|
element={
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1326
frontend/src/pages/EndpointEditor.tsx
Normal file
1326
frontend/src/pages/EndpointEditor.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,17 @@
|
|||||||
import { useState, useRef } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import { endpointsApi, databasesApi } from '@/services/api';
|
import { endpointsApi } from '@/services/api';
|
||||||
import { Endpoint, ImportPreviewResponse } from '@/types';
|
import { ImportPreviewResponse } from '@/types';
|
||||||
import { Plus, Search, Edit2, Trash2, Download, Upload } from 'lucide-react';
|
import { Plus, Search, Edit2, Trash2, Download, Upload } from 'lucide-react';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import EndpointModal from '@/components/EndpointModal';
|
|
||||||
import ImportEndpointModal from '@/components/ImportEndpointModal';
|
import ImportEndpointModal from '@/components/ImportEndpointModal';
|
||||||
import Dialog from '@/components/Dialog';
|
import Dialog from '@/components/Dialog';
|
||||||
|
|
||||||
export default function Endpoints() {
|
export default function Endpoints() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [showModal, setShowModal] = useState(false);
|
|
||||||
const [editingEndpoint, setEditingEndpoint] = useState<Endpoint | null>(null);
|
|
||||||
const [showImportModal, setShowImportModal] = useState(false);
|
const [showImportModal, setShowImportModal] = useState(false);
|
||||||
const [importFile, setImportFile] = useState<File | null>(null);
|
const [importFile, setImportFile] = useState<File | null>(null);
|
||||||
const [importPreview, setImportPreview] = useState<ImportPreviewResponse | null>(null);
|
const [importPreview, setImportPreview] = useState<ImportPreviewResponse | null>(null);
|
||||||
@@ -35,11 +34,6 @@ export default function Endpoints() {
|
|||||||
queryFn: () => endpointsApi.getAll(search).then(res => res.data),
|
queryFn: () => endpointsApi.getAll(search).then(res => res.data),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: databases } = useQuery({
|
|
||||||
queryKey: ['databases'],
|
|
||||||
queryFn: () => databasesApi.getAll().then(res => res.data),
|
|
||||||
});
|
|
||||||
|
|
||||||
const deleteMutation = useMutation({
|
const deleteMutation = useMutation({
|
||||||
mutationFn: (id: string) => endpointsApi.delete(id),
|
mutationFn: (id: string) => endpointsApi.delete(id),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -61,16 +55,6 @@ export default function Endpoints() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (endpoint: Endpoint) => {
|
|
||||||
setEditingEndpoint(endpoint);
|
|
||||||
setShowModal(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreate = () => {
|
|
||||||
setEditingEndpoint(null);
|
|
||||||
setShowModal(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleExport = async (endpointId: string, endpointName: string) => {
|
const handleExport = async (endpointId: string, endpointName: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await endpointsApi.exportEndpoint(endpointId);
|
const response = await endpointsApi.exportEndpoint(endpointId);
|
||||||
@@ -129,7 +113,7 @@ export default function Endpoints() {
|
|||||||
<Upload size={20} />
|
<Upload size={20} />
|
||||||
Импорт
|
Импорт
|
||||||
</button>
|
</button>
|
||||||
<button onClick={handleCreate} className="btn btn-primary flex items-center gap-2">
|
<button onClick={() => navigate('/endpoints/new')} className="btn btn-primary flex items-center gap-2">
|
||||||
<Plus size={20} />
|
<Plus size={20} />
|
||||||
Новый эндпоинт
|
Новый эндпоинт
|
||||||
</button>
|
</button>
|
||||||
@@ -203,7 +187,7 @@ export default function Endpoints() {
|
|||||||
<Download size={18} className="text-gray-600" />
|
<Download size={18} className="text-gray-600" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleEdit(endpoint)}
|
onClick={() => navigate(`/endpoints/${endpoint.id}`)}
|
||||||
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||||
title="Редактировать"
|
title="Редактировать"
|
||||||
>
|
>
|
||||||
@@ -229,14 +213,6 @@ export default function Endpoints() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showModal && (
|
|
||||||
<EndpointModal
|
|
||||||
endpoint={editingEndpoint}
|
|
||||||
databases={databases || []}
|
|
||||||
onClose={() => setShowModal(false)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{showImportModal && importPreview && importFile && (
|
{showImportModal && importPreview && importFile && (
|
||||||
<ImportEndpointModal
|
<ImportEndpointModal
|
||||||
preview={importPreview}
|
preview={importPreview}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import { foldersApi, endpointsApi, databasesApi } from '@/services/api';
|
import { foldersApi, endpointsApi } from '@/services/api';
|
||||||
import { Folder, Endpoint } from '@/types';
|
import { Folder, Endpoint } from '@/types';
|
||||||
import { Plus, Edit2, Trash2, Folder as FolderIcon, FolderOpen, FileCode, ChevronRight, ChevronDown } from 'lucide-react';
|
import { Plus, Edit2, Trash2, Folder as FolderIcon, FolderOpen, FileCode, ChevronRight, ChevronDown } from 'lucide-react';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import EndpointModal from '@/components/EndpointModal';
|
|
||||||
import Dialog from '@/components/Dialog';
|
import Dialog from '@/components/Dialog';
|
||||||
|
|
||||||
export default function Folders() {
|
export default function Folders() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [showFolderModal, setShowFolderModal] = useState(false);
|
const [showFolderModal, setShowFolderModal] = useState(false);
|
||||||
const [showEndpointModal, setShowEndpointModal] = useState(false);
|
|
||||||
const [editingFolder, setEditingFolder] = useState<Folder | null>(null);
|
const [editingFolder, setEditingFolder] = useState<Folder | null>(null);
|
||||||
const [editingEndpoint, setEditingEndpoint] = useState<Endpoint | null>(null);
|
|
||||||
const [selectedFolderId, setSelectedFolderId] = useState<string | null>(null);
|
const [selectedFolderId, setSelectedFolderId] = useState<string | null>(null);
|
||||||
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
|
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
|
||||||
const [dialog, setDialog] = useState<{
|
const [dialog, setDialog] = useState<{
|
||||||
@@ -38,11 +37,6 @@ export default function Folders() {
|
|||||||
queryFn: () => endpointsApi.getAll().then(res => res.data),
|
queryFn: () => endpointsApi.getAll().then(res => res.data),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: databases } = useQuery({
|
|
||||||
queryKey: ['databases'],
|
|
||||||
queryFn: () => databasesApi.getAll().then(res => res.data),
|
|
||||||
});
|
|
||||||
|
|
||||||
const deleteFolderMutation = useMutation({
|
const deleteFolderMutation = useMutation({
|
||||||
mutationFn: (id: string) => foldersApi.delete(id),
|
mutationFn: (id: string) => foldersApi.delete(id),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -74,14 +68,11 @@ export default function Folders() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateEndpoint = (folderId?: string) => {
|
const handleCreateEndpoint = (folderId?: string) => {
|
||||||
setSelectedFolderId(folderId || null);
|
navigate(folderId ? `/endpoints/new?folder=${folderId}` : '/endpoints/new');
|
||||||
setEditingEndpoint(null);
|
|
||||||
setShowEndpointModal(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditEndpoint = (endpoint: Endpoint) => {
|
const handleEditEndpoint = (endpoint: Endpoint) => {
|
||||||
setEditingEndpoint(endpoint);
|
navigate(`/endpoints/${endpoint.id}`);
|
||||||
setShowEndpointModal(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteFolder = (id: string) => {
|
const handleDeleteFolder = (id: string) => {
|
||||||
@@ -226,15 +217,6 @@ export default function Folders() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showEndpointModal && (
|
|
||||||
<EndpointModal
|
|
||||||
endpoint={editingEndpoint}
|
|
||||||
folderId={selectedFolderId}
|
|
||||||
databases={databases || []}
|
|
||||||
onClose={() => setShowEndpointModal(false)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen={dialog.isOpen}
|
isOpen={dialog.isOpen}
|
||||||
onClose={() => setDialog({ ...dialog, isOpen: false })}
|
onClose={() => setDialog({ ...dialog, isOpen: false })}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export interface EndpointParameter {
|
|||||||
required: boolean;
|
required: boolean;
|
||||||
default_value?: any;
|
default_value?: any;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
example_value?: string;
|
||||||
in: 'query' | 'body' | 'path';
|
in: 'query' | 'body' | 'path';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user