Fix unused GitBranch import + minor cleanup

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 01:43:49 +03:00
parent 44e4b45f50
commit c3f3c8c700
5 changed files with 39 additions and 113 deletions

View File

@@ -37,7 +37,6 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.49.2", "react-hook-form": "^7.49.2",
"react-hot-toast": "^2.4.1",
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-router-dom": "^6.20.1", "react-router-dom": "^6.20.1",
"sonner": "^2.0.7", "sonner": "^2.0.7",
@@ -3749,6 +3748,7 @@
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/d3-color": { "node_modules/d3-color": {
@@ -4682,15 +4682,6 @@
"url": "https://github.com/sponsors/sindresorhus" "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==",
"license": "MIT",
"peerDependencies": {
"csstype": "^3.0.10"
}
},
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -5706,23 +5697,6 @@
"react": "^16.8.0 || ^17 || ^18 || ^19" "react": "^16.8.0 || ^17 || ^18 || ^19"
} }
}, },
"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==",
"license": "MIT",
"dependencies": {
"csstype": "^3.1.3",
"goober": "^2.1.16"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/react-icons": { "node_modules/react-icons": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",

View File

@@ -43,7 +43,6 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.49.2", "react-hook-form": "^7.49.2",
"react-hot-toast": "^2.4.1",
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-router-dom": "^6.20.1", "react-router-dom": "^6.20.1",
"sonner": "^2.0.7", "sonner": "^2.0.7",

View File

@@ -57,28 +57,3 @@
} }
} }
@layer components {
.btn {
@apply px-4 py-2 rounded-lg font-medium transition-all duration-200;
}
.btn-primary {
@apply bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800;
}
.btn-secondary {
@apply bg-gray-200 text-gray-800 hover:bg-gray-300 active:bg-gray-400;
}
.btn-danger {
@apply bg-red-600 text-white hover:bg-red-700 active:bg-red-800;
}
.input-custom {
@apply px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent;
}
.card-custom {
@apply bg-white rounded-lg shadow-sm border border-gray-200;
}
}

View File

@@ -3,7 +3,7 @@ import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { endpointsApi, foldersApi, databasesApi, versionsApi, giteaApi } from '@/services/api'; import { endpointsApi, foldersApi, databasesApi, versionsApi, giteaApi } from '@/services/api';
import { EndpointParameter, QueryTestResult, LogEntry, QueryExecution, EndpointVersion } from '@/types'; import { EndpointParameter, QueryTestResult, LogEntry, QueryExecution, EndpointVersion } from '@/types';
import { Plus, Trash2, Play, Edit2, ChevronDown, ChevronUp, ArrowLeft, CheckCircle, XCircle, Clock, Copy, X, Terminal, History, RotateCcw, Upload, GitBranch } from 'lucide-react'; import { Plus, Trash2, Play, Edit2, ChevronDown, ChevronUp, ArrowLeft, CheckCircle, XCircle, Clock, Copy, X, Terminal, History, RotateCcw, Upload } from 'lucide-react';
import { toast } from 'sonner'; import { toast } from 'sonner';
import SqlEditor from '@/components/SqlEditor'; import SqlEditor from '@/components/SqlEditor';
import CodeEditor from '@/components/CodeEditor'; import CodeEditor from '@/components/CodeEditor';
@@ -903,35 +903,35 @@ export default function EndpointEditor() {
{/* Form buttons */} {/* Form buttons */}
<div className="flex gap-3 pt-4 border-t border-gray-200"> <div className="flex gap-3 pt-4 border-t border-gray-200">
<div className="flex-1"></div> <div className="flex-1"></div>
<button type="button" onClick={() => navigate(-1)} className="btn btn-secondary"> <Button type="button" variant="outline" onClick={() => navigate(-1)}>
Отмена Отмена
</button> </Button>
{isEditing && ( {isEditing && (
<button <Button
type="button" type="button"
variant="outline"
disabled={draftMutation?.isPending} disabled={draftMutation?.isPending}
className="btn bg-orange-50 text-orange-700 border border-orange-200 hover:bg-orange-100" className="bg-orange-50 text-orange-700 border-orange-200 hover:bg-orange-100"
onClick={() => draftMutation?.mutate()} onClick={() => draftMutation?.mutate()}
> >
{draftMutation?.isPending ? 'Сохранение...' : 'Save Draft'} {draftMutation?.isPending ? 'Сохранение...' : 'Save Draft'}
</button> </Button>
)} )}
<button <Button
type="submit" type="submit"
variant="outline"
disabled={saveMutation.isPending} disabled={saveMutation.isPending}
className="btn btn-secondary"
onClick={() => setSaveAndStay(true)} onClick={() => setSaveAndStay(true)}
> >
{saveMutation.isPending && saveAndStay ? 'Публикация...' : 'Publish'} {saveMutation.isPending && saveAndStay ? 'Публикация...' : 'Publish'}
</button> </Button>
<button <Button
type="submit" type="submit"
disabled={saveMutation.isPending} disabled={saveMutation.isPending}
className="btn btn-primary"
onClick={() => setSaveAndStay(false)} onClick={() => setSaveAndStay(false)}
> >
{saveMutation.isPending && !saveAndStay ? 'Публикация...' : 'Publish & Exit'} {saveMutation.isPending && !saveAndStay ? 'Публикация...' : 'Publish & Exit'}
</button> </Button>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -941,7 +941,7 @@ export default function EndpointEditor() {
<div className="flex-[2] min-w-0 space-y-4"> <div className="flex-[2] min-w-0 space-y-4">
{/* Test parameters */} {/* Test parameters */}
{formData.parameters.length > 0 && ( {formData.parameters.length > 0 && (
<div className="card p-4"> <div className="rounded-lg border bg-card shadow-sm p-4">
<label className="block text-sm font-medium text-gray-700 mb-3"> <label className="block text-sm font-medium text-gray-700 mb-3">
Тестовые параметры Тестовые параметры
</label> </label>
@@ -956,7 +956,7 @@ export default function EndpointEditor() {
<select <select
value={testParams[param.name] || ''} value={testParams[param.name] || ''}
onChange={(e) => setTestParams({ ...testParams, [param.name]: e.target.value })} onChange={(e) => setTestParams({ ...testParams, [param.name]: e.target.value })}
className="input w-full text-sm" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
> >
<option value="">Не задано</option> <option value="">Не задано</option>
<option value="true">true</option> <option value="true">true</option>
@@ -968,7 +968,7 @@ export default function EndpointEditor() {
placeholder={param.example_value || param.description || `Введите ${param.name}`} placeholder={param.example_value || param.description || `Введите ${param.name}`}
value={testParams[param.name] || ''} value={testParams[param.name] || ''}
onChange={(e) => setTestParams({ ...testParams, [param.name]: e.target.value })} onChange={(e) => setTestParams({ ...testParams, [param.name]: e.target.value })}
className="input w-full text-sm" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
/> />
)} )}
</div> </div>
@@ -978,7 +978,7 @@ export default function EndpointEditor() {
)} )}
{/* Environment toggle + Test button */} {/* Environment toggle + Test button */}
<div className="card p-4 space-y-3"> <div className="rounded-lg border bg-card shadow-sm p-4 space-y-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="text-xs font-medium text-gray-500">Среда:</span> <span className="text-xs font-medium text-gray-500">Среда:</span>
<div className="flex rounded-lg overflow-hidden border border-gray-200"> <div className="flex rounded-lg overflow-hidden border border-gray-200">
@@ -1009,7 +1009,7 @@ export default function EndpointEditor() {
<span className="text-xs text-amber-600">Test env не настроена fallback на prod</span> <span className="text-xs text-amber-600">Test env не настроена fallback на prod</span>
)} )}
</div> </div>
<button <Button
type="button" type="button"
onClick={() => testMutation.mutate()} onClick={() => testMutation.mutate()}
disabled={ disabled={
@@ -1021,19 +1021,19 @@ export default function EndpointEditor() {
: !formData.script_code : !formData.script_code
) )
} }
className={`btn w-full flex items-center justify-center gap-2 ${ className={`w-full ${
testEnvironment === 'test' testEnvironment === 'test'
? 'bg-orange-500 hover:bg-orange-600 text-white' ? 'bg-orange-500 hover:bg-orange-600 text-white'
: 'btn-primary' : ''
}`} }`}
> >
<Play size={18} /> <Play className="mr-2 h-4 w-4" />
{testMutation.isPending ? 'Тестирование...' : `Тест (${testEnvironment})`} {testMutation.isPending ? 'Тестирование...' : `Тест (${testEnvironment})`}
</button> </Button>
</div> </div>
{/* cURL generator */} {/* cURL generator */}
<div className="card p-4"> <div className="rounded-lg border bg-card shadow-sm p-4">
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Terminal size={16} className="text-gray-600" /> <Terminal size={16} className="text-gray-600" />
@@ -1054,7 +1054,7 @@ export default function EndpointEditor() {
placeholder="X-API-Key (необязательно)" placeholder="X-API-Key (необязательно)"
value={curlApiKey} value={curlApiKey}
onChange={(e) => setCurlApiKey(e.target.value)} onChange={(e) => setCurlApiKey(e.target.value)}
className="input w-full text-sm" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
/> />
</div> </div>
<pre className="text-xs font-mono bg-gray-900 text-green-400 p-3 rounded-lg overflow-x-auto whitespace-pre-wrap max-h-48"> <pre className="text-xs font-mono bg-gray-900 text-green-400 p-3 rounded-lg overflow-x-auto whitespace-pre-wrap max-h-48">
@@ -1064,7 +1064,7 @@ export default function EndpointEditor() {
{/* Version History */} {/* Version History */}
{isEditing && ( {isEditing && (
<div className="card p-4"> <div className="rounded-lg border bg-card shadow-sm p-4">
<button <button
type="button" type="button"
onClick={() => setShowVersionHistory(!showVersionHistory)} onClick={() => setShowVersionHistory(!showVersionHistory)}
@@ -1147,7 +1147,7 @@ export default function EndpointEditor() {
{/* Test results */} {/* Test results */}
{testResult && ( {testResult && (
<div className="card overflow-hidden"> <div className="rounded-lg border bg-card shadow-sm overflow-hidden">
{/* Status bar */} {/* Status bar */}
<div className={`flex items-center justify-between px-4 py-2 ${testResult.success ? 'bg-green-50 border-b border-green-200' : 'bg-red-50 border-b border-red-200'}`}> <div className={`flex items-center justify-between px-4 py-2 ${testResult.success ? 'bg-green-50 border-b border-green-200' : 'bg-red-50 border-b border-red-200'}`}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -1360,7 +1360,7 @@ export default function EndpointEditor() {
newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], name: e.target.value }; newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], name: e.target.value };
setFormData({ ...formData, script_queries: newQueries }); setFormData({ ...formData, script_queries: newQueries });
}} }}
className="input w-full" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
/> />
</div> </div>
<div> <div>
@@ -1373,7 +1373,7 @@ export default function EndpointEditor() {
newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], database_id: e.target.value }; newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], database_id: e.target.value };
setFormData({ ...formData, script_queries: newQueries }); setFormData({ ...formData, script_queries: newQueries });
}} }}
className="input w-full" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
> >
<option value="">Выберите базу данных</option> <option value="">Выберите базу данных</option>
{databases?.map((db) => ( {databases?.map((db) => (
@@ -1397,7 +1397,7 @@ export default function EndpointEditor() {
newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], aql_method: e.target.value as any }; newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], aql_method: e.target.value as any };
setFormData({ ...formData, script_queries: newQueries }); setFormData({ ...formData, script_queries: newQueries });
}} }}
className="input w-full" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
> >
<option value="GET">GET</option> <option value="GET">GET</option>
<option value="POST">POST</option> <option value="POST">POST</option>
@@ -1419,7 +1419,7 @@ export default function EndpointEditor() {
newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], aql_endpoint: e.target.value }; newQueries[editingQueryIndex] = { ...newQueries[editingQueryIndex], aql_endpoint: e.target.value };
setFormData({ ...formData, script_queries: newQueries }); setFormData({ ...formData, script_queries: newQueries });
}} }}
className="input w-full" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
placeholder="/query" placeholder="/query"
/> />
</div> </div>
@@ -1478,20 +1478,12 @@ export default function EndpointEditor() {
})()} })()}
</div> </div>
<div className="p-6 border-t border-gray-200 flex gap-3"> <div className="p-6 border-t border-gray-200 flex gap-3">
<button <Button type="button" onClick={() => setEditingQueryIndex(null)}>
type="button"
onClick={() => setEditingQueryIndex(null)}
className="btn btn-primary"
>
Сохранить Сохранить
</button> </Button>
<button <Button type="button" variant="outline" onClick={() => setEditingQueryIndex(null)}>
type="button"
onClick={() => setEditingQueryIndex(null)}
className="btn btn-secondary"
>
Закрыть Закрыть
</button> </Button>
</div> </div>
</div> </div>
</div> </div>
@@ -1527,20 +1519,12 @@ export default function EndpointEditor() {
/> />
</div> </div>
<div className="p-6 border-t border-gray-200 flex gap-3"> <div className="p-6 border-t border-gray-200 flex gap-3">
<button <Button type="button" onClick={() => setShowScriptCodeEditor(false)}>
type="button"
onClick={() => setShowScriptCodeEditor(false)}
className="btn btn-primary"
>
Сохранить Сохранить
</button> </Button>
<button <Button type="button" variant="outline" onClick={() => setShowScriptCodeEditor(false)}>
type="button"
onClick={() => setShowScriptCodeEditor(false)}
className="btn btn-secondary"
>
Закрыть Закрыть
</button> </Button>
</div> </div>
</div> </div>
</div> </div>
@@ -1586,7 +1570,7 @@ function FolderSelector({ value, onChange }: { value: string; onChange: (value:
const folderList = buildFolderList(); const folderList = buildFolderList();
return ( return (
<select value={value} onChange={(e) => onChange(e.target.value)} className="input w-full"> <select value={value} onChange={(e) => onChange(e.target.value)} className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring">
<option value="">Без папки</option> <option value="">Без папки</option>
{folderList.map((folder) => ( {folderList.map((folder) => (
<option key={folder.id} value={folder.id}> <option key={folder.id} value={folder.id}>

View File

@@ -1,6 +0,0 @@
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}