modified: backend/src/services/DatabasePoolManager.ts
modified: backend/src/services/ScriptExecutor.ts modified: backend/src/types/index.ts modified: frontend/src/components/CodeEditor.tsx modified: frontend/src/components/EndpointModal.tsx deleted: frontend/src/pages/Databases.tsx modified: frontend/src/pages/Settings.tsx modified: frontend/src/types/index.ts
This commit is contained in:
@@ -3,7 +3,7 @@ import Editor from '@monaco-editor/react';
|
||||
interface CodeEditorProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
language: 'javascript' | 'python';
|
||||
language: 'javascript' | 'python' | 'json';
|
||||
height?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -377,38 +377,43 @@ export default function EndpointModal({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">AQL Body (JSON)</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">AQL Body (JSON)</label>
|
||||
<div className="mb-2 p-2 bg-blue-50 border border-blue-200 rounded text-xs text-blue-700">
|
||||
<div>Используйте <code className="bg-blue-100 px-1 rounded">$параметр</code> в JSON для подстановки</div>
|
||||
</div>
|
||||
<textarea
|
||||
<CodeEditor
|
||||
value={formData.aql_body}
|
||||
onChange={(e) => setFormData({ ...formData, aql_body: e.target.value })}
|
||||
className="input w-full font-mono text-sm"
|
||||
rows={6}
|
||||
placeholder='{"aql": "select c from COMPOSITION c where c/uid/value= '$compositionId'"}'
|
||||
onChange={(value) => setFormData({ ...formData, aql_body: value })}
|
||||
language="json"
|
||||
height="150px"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
Пример: {`{"aql": "select c from COMPOSITION c where c/uid/value='$compositionId'"}`}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">AQL Query Parameters (JSON)</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">AQL Query Parameters (JSON)</label>
|
||||
<div className="mb-2 p-2 bg-blue-50 border border-blue-200 rounded text-xs text-blue-700">
|
||||
<div>Формат: <code className="bg-blue-100 px-1 rounded">{`{"key": "value", "CompositionLink": "$linkValue"}`}</code></div>
|
||||
</div>
|
||||
<textarea
|
||||
<CodeEditor
|
||||
value={typeof formData.aql_query_params === 'string' ? formData.aql_query_params : JSON.stringify(formData.aql_query_params, null, 2)}
|
||||
onChange={(e) => {
|
||||
onChange={(value) => {
|
||||
try {
|
||||
const parsed = JSON.parse(e.target.value);
|
||||
const parsed = JSON.parse(value);
|
||||
setFormData({ ...formData, aql_query_params: parsed });
|
||||
} catch {
|
||||
// Игнорируем невалидный JSON - не обновляем состояние
|
||||
// Сохраняем невалидный JSON как строку для последующего редактирования
|
||||
setFormData({ ...formData, aql_query_params: value as any });
|
||||
}
|
||||
}}
|
||||
className="input w-full font-mono text-sm"
|
||||
rows={4}
|
||||
placeholder='{"CompositionLink": "ehr:compositions/$compositionId"}'
|
||||
language="json"
|
||||
height="120px"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
Пример: {`{"CompositionLink": "ehr:compositions/$compositionId"}`}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
) : formData.execution_type === 'sql' ? (
|
||||
@@ -450,7 +455,15 @@ export default function EndpointModal({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const newQueries = [...formData.script_queries, { name: '', sql: '', database_id: '' }];
|
||||
const newQueries = [...formData.script_queries, {
|
||||
name: '',
|
||||
sql: '',
|
||||
database_id: '',
|
||||
aql_method: 'GET' as 'GET' | 'POST' | 'PUT' | 'DELETE',
|
||||
aql_endpoint: '',
|
||||
aql_body: '',
|
||||
aql_query_params: {}
|
||||
}];
|
||||
setFormData({ ...formData, script_queries: newQueries });
|
||||
setEditingQueryIndex(newQueries.length - 1);
|
||||
}}
|
||||
@@ -469,9 +482,14 @@ export default function EndpointModal({
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<code className="text-sm font-semibold text-gray-900">{query.name || 'Безымянный запрос'}</code>
|
||||
{query.database_id && (
|
||||
<span className="text-xs text-gray-500">
|
||||
→ {databases.find(db => db.id === query.database_id)?.name || 'БД не выбрана'}
|
||||
</span>
|
||||
<>
|
||||
<span className="text-xs text-gray-500">
|
||||
→ {databases.find(db => db.id === query.database_id)?.name || 'БД не выбрана'}
|
||||
</span>
|
||||
{databases.find(db => db.id === query.database_id)?.type === 'aql' && (
|
||||
<span className="text-xs bg-purple-100 text-purple-700 px-2 py-0.5 rounded">AQL</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{query.sql && (
|
||||
@@ -479,6 +497,11 @@ export default function EndpointModal({
|
||||
{query.sql.substring(0, 100)}{query.sql.length > 100 ? '...' : ''}
|
||||
</div>
|
||||
)}
|
||||
{query.aql_endpoint && (
|
||||
<div className="text-xs text-gray-600 font-mono bg-purple-50 p-2 rounded mt-1">
|
||||
<span className="text-purple-700 font-semibold">{query.aql_method}</span> {query.aql_endpoint}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2 ml-4">
|
||||
<button
|
||||
@@ -666,22 +689,112 @@ export default function EndpointModal({
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">SQL Запрос</label>
|
||||
<div className="mb-2 p-2 bg-blue-50 border border-blue-200 rounded text-xs text-blue-700">
|
||||
<div><strong>Совет:</strong> Используйте <code className="bg-blue-100 px-1 rounded">$имяПараметра</code> для параметров из запроса или дополнительных параметров из скрипта.</div>
|
||||
</div>
|
||||
<SqlEditor
|
||||
value={formData.script_queries[editingQueryIndex]?.sql || ''}
|
||||
onChange={(value) => {
|
||||
const newQueries = [...formData.script_queries];
|
||||
newQueries[editingQueryIndex].sql = value;
|
||||
setFormData({ ...formData, script_queries: newQueries });
|
||||
}}
|
||||
databaseId={formData.script_queries[editingQueryIndex]?.database_id || ''}
|
||||
height="400px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Определяем тип выбранной базы данных */}
|
||||
{(() => {
|
||||
const selectedDb = databases.find(db => db.id === formData.script_queries[editingQueryIndex]?.database_id);
|
||||
const isAql = selectedDb?.type === 'aql';
|
||||
|
||||
return isAql ? (
|
||||
<>
|
||||
{/* AQL Fields */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">AQL HTTP Метод</label>
|
||||
<select
|
||||
value={formData.script_queries[editingQueryIndex]?.aql_method || 'GET'}
|
||||
onChange={(e) => {
|
||||
const newQueries = [...formData.script_queries];
|
||||
newQueries[editingQueryIndex].aql_method = e.target.value as any;
|
||||
setFormData({ ...formData, script_queries: newQueries });
|
||||
}}
|
||||
className="input w-full"
|
||||
>
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">AQL Endpoint URL</label>
|
||||
<div className="mb-2 p-2 bg-blue-50 border border-blue-200 rounded text-xs text-blue-700">
|
||||
<div>Используйте <code className="bg-blue-100 px-1 rounded">$параметр</code> для подстановки</div>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
value={formData.script_queries[editingQueryIndex]?.aql_endpoint || ''}
|
||||
onChange={(e) => {
|
||||
const newQueries = [...formData.script_queries];
|
||||
newQueries[editingQueryIndex].aql_endpoint = e.target.value;
|
||||
setFormData({ ...formData, script_queries: newQueries });
|
||||
}}
|
||||
className="input w-full"
|
||||
placeholder="/query"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">AQL Body (JSON)</label>
|
||||
<div className="mb-2 p-2 bg-blue-50 border border-blue-200 rounded text-xs text-blue-700">
|
||||
<div>Используйте <code className="bg-blue-100 px-1 rounded">$параметр</code> в JSON для подстановки</div>
|
||||
</div>
|
||||
<CodeEditor
|
||||
value={formData.script_queries[editingQueryIndex]?.aql_body || ''}
|
||||
onChange={(value) => {
|
||||
const newQueries = [...formData.script_queries];
|
||||
newQueries[editingQueryIndex].aql_body = value;
|
||||
setFormData({ ...formData, script_queries: newQueries });
|
||||
}}
|
||||
language="json"
|
||||
height="200px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">AQL Query Parameters (JSON)</label>
|
||||
<CodeEditor
|
||||
value={typeof formData.script_queries[editingQueryIndex]?.aql_query_params === 'string'
|
||||
? formData.script_queries[editingQueryIndex]?.aql_query_params
|
||||
: JSON.stringify(formData.script_queries[editingQueryIndex]?.aql_query_params || {}, null, 2)}
|
||||
onChange={(value) => {
|
||||
const newQueries = [...formData.script_queries];
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
newQueries[editingQueryIndex].aql_query_params = parsed;
|
||||
} catch {
|
||||
newQueries[editingQueryIndex].aql_query_params = value as any;
|
||||
}
|
||||
setFormData({ ...formData, script_queries: newQueries });
|
||||
}}
|
||||
language="json"
|
||||
height="150px"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{/* SQL Field */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">SQL Запрос</label>
|
||||
<div className="mb-2 p-2 bg-blue-50 border border-blue-200 rounded text-xs text-blue-700">
|
||||
<div><strong>Совет:</strong> Используйте <code className="bg-blue-100 px-1 rounded">$имяПараметра</code> для параметров из запроса или дополнительных параметров из скрипта.</div>
|
||||
</div>
|
||||
<SqlEditor
|
||||
value={formData.script_queries[editingQueryIndex]?.sql || ''}
|
||||
onChange={(value) => {
|
||||
const newQueries = [...formData.script_queries];
|
||||
newQueries[editingQueryIndex].sql = value;
|
||||
setFormData({ ...formData, script_queries: newQueries });
|
||||
}}
|
||||
databaseId={formData.script_queries[editingQueryIndex]?.database_id || ''}
|
||||
height="400px"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
<div className="p-6 border-t border-gray-200 flex gap-3">
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user