Add CodeMirror SQL editor with autocomplete for tables and columns
This commit is contained in:
@@ -5,6 +5,15 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">␍
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">␍
|
||||||
<title>RIPS Manager - {% block title %}Dashboard{% endblock %}</title>␍
|
<title>RIPS Manager - {% block title %}Dashboard{% endblock %}</title>␍
|
||||||
<script src="https://cdn.tailwindcss.com"></script>␍
|
<script src="https://cdn.tailwindcss.com"></script>␍
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">␍
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>␍
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/sql/sql.min.js"></script>␍
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/hint/show-hint.min.js"></script>␍
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/hint/sql-hint.min.js"></script>␍
|
||||||
|
<style>␍
|
||||||
|
.CodeMirror { border: 1px solid #d1d5db; border-radius: 0.5rem; font-size: 13px; height: auto; min-height: 200px; }␍
|
||||||
|
.CodeMirror-hints { font-size: 12px; }␍
|
||||||
|
</style>␍
|
||||||
<script>␍
|
<script>␍
|
||||||
tailwind.config = {␍
|
tailwind.config = {␍
|
||||||
theme: {␍
|
theme: {␍
|
||||||
|
|||||||
@@ -56,7 +56,8 @@
|
|||||||
</div>␍
|
</div>␍
|
||||||
<div>␍
|
<div>␍
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Consulta SQL</label>␍
|
<label class="block text-sm font-medium text-gray-700 mb-1">Consulta SQL</label>␍
|
||||||
<textarea name="query_text" id="q_text" rows="10" required class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm font-mono bg-gray-50" placeholder="SELECT ... FROM ... WHERE ..."></textarea>
|
<textarea name="query_text" id="q_text" rows="10" required class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm font-mono bg-gray-50" placeholder="SELECT ... FROM ... WHERE ..." style="display:none"></textarea>␍
|
||||||
|
<div id="sql-editor-wrapper"></div>␍
|
||||||
</div>␍
|
</div>␍
|
||||||
<div>␍
|
<div>␍
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Descripción</label>␍
|
<label class="block text-sm font-medium text-gray-700 mb-1">Descripción</label>␍
|
||||||
@@ -332,6 +333,7 @@ function usarSql() {
|
|||||||
const sql = document.getElementById('builder-sql').value;␍
|
const sql = document.getElementById('builder-sql').value;␍
|
||||||
if (!sql || sql.startsWith('--')) { showToast('No hay SQL generado', 'warning'); return; }␍
|
if (!sql || sql.startsWith('--')) { showToast('No hay SQL generado', 'warning'); return; }␍
|
||||||
document.getElementById('q_text').value = sql;␍
|
document.getElementById('q_text').value = sql;␍
|
||||||
|
if (sqlEditor) sqlEditor.setValue(sql);␍
|
||||||
mostrarEditor();␍
|
mostrarEditor();␍
|
||||||
showToast('SQL copiado al editor');␍
|
showToast('SQL copiado al editor');␍
|
||||||
}␍
|
}␍
|
||||||
@@ -351,6 +353,7 @@ function editQuery(id, name, type, text, desc) {
|
|||||||
document.getElementById('q_desc').value = desc;␍
|
document.getElementById('q_desc').value = desc;␍
|
||||||
document.getElementById('btn-cancel').classList.remove('hidden');␍
|
document.getElementById('btn-cancel').classList.remove('hidden');␍
|
||||||
document.querySelector('form').action = '/queries/update/' + id;␍
|
document.querySelector('form').action = '/queries/update/' + id;␍
|
||||||
|
if (sqlEditor) sqlEditor.setValue(text);␍
|
||||||
}␍
|
}␍
|
||||||
function cancelEdit() {␍
|
function cancelEdit() {␍
|
||||||
document.getElementById('query_id').value = '';␍
|
document.getElementById('query_id').value = '';␍
|
||||||
@@ -359,6 +362,7 @@ function cancelEdit() {
|
|||||||
document.getElementById('q_desc').value = '';␍
|
document.getElementById('q_desc').value = '';␍
|
||||||
document.getElementById('btn-cancel').classList.add('hidden');␍
|
document.getElementById('btn-cancel').classList.add('hidden');␍
|
||||||
document.querySelector('form').action = '/queries/create';␍
|
document.querySelector('form').action = '/queries/create';␍
|
||||||
|
if (sqlEditor) sqlEditor.setValue('');␍
|
||||||
}␍
|
}␍
|
||||||
async function listarTablas(btn) {␍
|
async function listarTablas(btn) {␍
|
||||||
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-1"></i> Cargando...';␍
|
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-1"></i> Cargando...';␍
|
||||||
@@ -374,6 +378,50 @@ async function listarTablas(btn) {
|
|||||||
} catch(e) { showToast('Error: ' + e.message, 'error'); }␍
|
} catch(e) { showToast('Error: ' + e.message, 'error'); }␍
|
||||||
finally { btn.disabled = false; btn.innerHTML = '<i class="fas fa-table mr-1"></i> Ver tablas disponibles'; }␍
|
finally { btn.disabled = false; btn.innerHTML = '<i class="fas fa-table mr-1"></i> Ver tablas disponibles'; }␍
|
||||||
}␍
|
}␍
|
||||||
|
let sqlEditor = null;␍
|
||||||
|
␍
|
||||||
|
async function initSqlEditor() {␍
|
||||||
|
sqlEditor = CodeMirror(document.getElementById('sql-editor-wrapper'), {␍
|
||||||
|
value: document.getElementById('q_text').value,␍
|
||||||
|
mode: 'text/x-sql',␍
|
||||||
|
lineNumbers: true,␍
|
||||||
|
indentWithTabs: true,␍
|
||||||
|
smartIndent: true,␍
|
||||||
|
lineWrapping: true,␍
|
||||||
|
extraKeys: {␍
|
||||||
|
'Ctrl-Space': 'autocomplete'␍
|
||||||
|
},␍
|
||||||
|
hintOptions: {␍
|
||||||
|
tables: {},␍
|
||||||
|
words: ['SELECT','FROM','WHERE','AND','OR','JOIN','LEFT','RIGHT','INNER','OUTER','ON','AS','IN','NOT','NULL','IS','LIKE','BETWEEN','INTO','VALUES','SET','UPDATE','DELETE','INSERT','CREATE','ALTER','DROP','TABLE','INDEX','VIEW','ORDER','BY','GROUP','HAVING','DISTINCT','COUNT','SUM','AVG','MIN','MAX','BETWEEN','EXISTS','UNION','ALL','ANY','CASE','WHEN','THEN','ELSE','END','CAST','COALESCE','NULLIF','DESC','ASC']␍
|
||||||
|
}␍
|
||||||
|
});␍
|
||||||
|
␍
|
||||||
|
sqlEditor.on('change', function() {␍
|
||||||
|
document.getElementById('q_text').value = sqlEditor.getValue();␍
|
||||||
|
});␍
|
||||||
|
␍
|
||||||
|
// Cargar esquema para autocomplete␍
|
||||||
|
try {␍
|
||||||
|
const resp = await fetch('/queries/esquema', { method: 'POST' });␍
|
||||||
|
const data = await resp.json();␍
|
||||||
|
if (!data.error && data.tablas) {␍
|
||||||
|
const tables = {};␍
|
||||||
|
data.tablas.forEach(t => {␍
|
||||||
|
tables[t.tabla] = t.columnas.map(c => c.nombre);␍
|
||||||
|
});␍
|
||||||
|
sqlEditor.setOption('hintOptions', { tables });␍
|
||||||
|
}␍
|
||||||
|
} catch(e) {}␍
|
||||||
|
}␍
|
||||||
|
␍
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {␍
|
||||||
|
document.querySelector('form').addEventListener('submit', function() {␍
|
||||||
|
document.getElementById('q_text').value = sqlEditor ? sqlEditor.getValue() : document.getElementById('q_text').value;␍
|
||||||
|
});␍
|
||||||
|
initSqlEditor();␍
|
||||||
|
});␍
|
||||||
|
␍
|
||||||
async function ejecutarTest(btn, queryId) {␍
|
async function ejecutarTest(btn, queryId) {␍
|
||||||
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-1"></i> Probando...';␍
|
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-1"></i> Probando...';␍
|
||||||
try {␍
|
try {␍
|
||||||
|
|||||||
Reference in New Issue
Block a user