feat(query-runner): helpers DBA para conexiones SQL
- Chips rápidos: SHOW DATABASES, SHOW TABLES, SHOW USERS, SHOW GRANTS, SHOW PROCESSLIST, SHOW CREATE TABLE, DESCRIBE, info_schema engine/charset - Generador DBA (collapsible): form con BD, usuario, host y contraseña Operaciones: Setup completo | CREATE DATABASE | CREATE USER | GRANT ALL | REVOKE | SHOW GRANTS | DROP USER | DROP DATABASE - Setup completo genera las 3 sentencias en bloque con comentarios - Visible só Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot
parent
3114a2da6c
commit
34f2c3e582
@@ -174,6 +174,83 @@
|
||||
class="w-full bg-gray-900 text-gray-100 font-mono text-sm p-4 resize-none outline-none leading-relaxed"
|
||||
style="height:180px; tab-size:2;"></textarea>
|
||||
</div>
|
||||
<!-- ─── Helpers SQL (solo MySQL/PostgreSQL) ─── -->
|
||||
<div x-show="!isMongo && selectedConxId" class="mt-1.5">
|
||||
<!-- Chips rápidos -->
|
||||
<div class="flex flex-wrap gap-1 mb-1.5">
|
||||
<template x-for="h in sqlHelpers" :key="h.label">
|
||||
<button @click="sqlText = h.cmd" class="text-[10px] px-2 py-0.5 rounded bg-gray-100 hover:bg-gray-200 text-gray-600 font-mono transition" x-text="h.label"></button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- ══ Generador DBA ══ -->
|
||||
<div class="border rounded-lg overflow-hidden">
|
||||
<button @click="showDbHelper = !showDbHelper"
|
||||
class="w-full flex items-center gap-1.5 px-3 py-1.5 bg-gray-50 hover:bg-[#e9f0cf] text-xs text-gray-600 transition text-left select-none">
|
||||
<svg class="w-3 h-3 transition-transform duration-150" :class="showDbHelper ? 'rotate-90' : ''"
|
||||
fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
<span class="font-semibold">Generador DBA</span>
|
||||
<span class="ml-auto text-[10px] text-gray-400">CREATE · GRANT · DROP · Setup</span>
|
||||
</button>
|
||||
<div x-show="showDbHelper" x-transition class="p-3 bg-white border-t">
|
||||
<div class="grid grid-cols-2 gap-2 text-xs">
|
||||
<div>
|
||||
<label class="text-[10px] text-gray-500 font-semibold uppercase block mb-0.5">Nombre BD</label>
|
||||
<input x-model="dbHelper.db" list="dba-dbs"
|
||||
class="w-full border rounded px-2 py-1 font-mono focus:outline-none focus:ring-1 focus:ring-[#8eb02f]"
|
||||
placeholder="mi_base_datos">
|
||||
<datalist id="dba-dbs">
|
||||
<template x-for="d in databases" :key="d"><option :value="d"></option></template>
|
||||
</datalist>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-[10px] text-gray-500 font-semibold uppercase block mb-0.5">Operación</label>
|
||||
<select x-model="dbHelper.op" class="w-full border rounded px-2 py-1 focus:outline-none focus:ring-1 focus:ring-[#8eb02f]">
|
||||
<option value="full_setup">✦ Setup completo (BD + usuario + permisos)</option>
|
||||
<option value="create_db">Crear base de datos</option>
|
||||
<option value="create_user">Crear usuario</option>
|
||||
<option value="grant">Dar permisos totales (GRANT ALL)</option>
|
||||
<option value="revoke">Revocar permisos</option>
|
||||
<option value="show_grants">Ver permisos de usuario</option>
|
||||
<option value="drop_user">Eliminar usuario</option>
|
||||
<option value="drop_db">Eliminar base de datos</option>
|
||||
</select>
|
||||
</div>
|
||||
<div x-show="['full_setup','create_user','grant','revoke','show_grants','drop_user'].includes(dbHelper.op)">
|
||||
<label class="text-[10px] text-gray-500 font-semibold uppercase block mb-0.5">Usuario</label>
|
||||
<input x-model="dbHelper.user"
|
||||
class="w-full border rounded px-2 py-1 font-mono focus:outline-none focus:ring-1 focus:ring-[#8eb02f]"
|
||||
placeholder="usuario_app">
|
||||
</div>
|
||||
<div x-show="['full_setup','create_user','grant','revoke','show_grants','drop_user'].includes(dbHelper.op)">
|
||||
<label class="text-[10px] text-gray-500 font-semibold uppercase block mb-0.5">Host</label>
|
||||
<input x-model="dbHelper.host"
|
||||
class="w-full border rounded px-2 py-1 font-mono focus:outline-none focus:ring-1 focus:ring-[#8eb02f]"
|
||||
placeholder="%">
|
||||
</div>
|
||||
<div x-show="['full_setup','create_user'].includes(dbHelper.op)" class="col-span-2">
|
||||
<label class="text-[10px] text-gray-500 font-semibold uppercase block mb-0.5">Contraseña</label>
|
||||
<input x-model="dbHelper.pass" type="text"
|
||||
class="w-full border rounded px-2 py-1 font-mono focus:outline-none focus:ring-1 focus:ring-[#8eb02f]"
|
||||
placeholder="Contraseña segura">
|
||||
<p class="text-[9px] text-gray-400 mt-0.5">Se insertará tal cual en el SQL generado.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mt-2.5 pt-2.5 border-t">
|
||||
<button @click="generateDbHelper()"
|
||||
class="flex-1 py-1.5 text-xs text-white font-semibold rounded transition"
|
||||
style="background-color:#8eb02f"
|
||||
onmouseover="this.style.backgroundColor='#6d8c24'"
|
||||
onmouseout="this.style.backgroundColor='#8eb02f'">
|
||||
↗ Generar en editor
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ayuda rápida MongoDB -->
|
||||
<div x-show="isMongo" class="mt-1.5">
|
||||
<div class="flex flex-wrap gap-1 mb-1.5">
|
||||
@@ -369,6 +446,20 @@ document.addEventListener('alpine:init', () => {
|
||||
loadingFields: false,
|
||||
showUpdateBuilder: false,
|
||||
updateBuilder: { collection: '', field: '', value: '', filterField: '_id', filterValue: '""', op: '$set', multi: 'one' },
|
||||
|
||||
// SQL DBA helpers
|
||||
showDbHelper: false,
|
||||
dbHelper: { db: '', user: '', pass: '', host: '%', op: 'full_setup' },
|
||||
sqlHelpers: [
|
||||
{ label: 'SHOW DATABASES', cmd: 'SHOW DATABASES;' },
|
||||
{ label: 'SHOW TABLES', cmd: 'SHOW TABLES;' },
|
||||
{ label: 'SHOW USERS', cmd: "SELECT User, Host, plugin FROM mysql.user ORDER BY User;" },
|
||||
{ label: 'SHOW GRANTS (actual)',cmd: 'SHOW GRANTS FOR CURRENT_USER;' },
|
||||
{ label: 'SHOW PROCESSLIST', cmd: 'SHOW FULL PROCESSLIST;' },
|
||||
{ label: 'SHOW CREATE TABLE', cmd: 'SHOW CREATE TABLE nombre_tabla;' },
|
||||
{ label: 'DESC tabla', cmd: 'DESCRIBE nombre_tabla;' },
|
||||
{ label: 'ENGINE/CHARSET', cmd: "SELECT table_name, engine, table_collation FROM information_schema.tables WHERE table_schema = DATABASE();" },
|
||||
],
|
||||
mongoExamples: [
|
||||
{ label: 'find()', cmd: 'db.coleccion.find({})' },
|
||||
{ label: 'findOne()', cmd: 'db.coleccion.findOne({})' },
|
||||
@@ -603,6 +694,35 @@ document.addEventListener('alpine:init', () => {
|
||||
this.sqlText = `db.${col}.${method}(\n { "${filterField}": ${filterValue} },\n { "${op}": ${updateDoc} }\n)`;
|
||||
},
|
||||
|
||||
generateDbHelper() {
|
||||
const db = this.dbHelper.db || 'nombre_bd';
|
||||
const user = this.dbHelper.user || 'usuario_app';
|
||||
const host = this.dbHelper.host || '%';
|
||||
const pass = this.dbHelper.pass || 'Contraseña123!';
|
||||
|
||||
const createDb = `CREATE DATABASE IF NOT EXISTS \`${db}\`\n CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`;
|
||||
const createUser = `CREATE USER IF NOT EXISTS '${user}'@'${host}' IDENTIFIED BY '${pass}';`;
|
||||
const grant = `GRANT ALL PRIVILEGES ON \`${db}\`.* TO '${user}'@'${host}';\nFLUSH PRIVILEGES;`;
|
||||
const revoke = `REVOKE ALL PRIVILEGES ON \`${db}\`.* FROM '${user}'@'${host}';\nFLUSH PRIVILEGES;`;
|
||||
const showGrants = `SHOW GRANTS FOR '${user}'@'${host}';`;
|
||||
const dropUser = `DROP USER IF EXISTS '${user}'@'${host}';\nFLUSH PRIVILEGES;`;
|
||||
const dropDb = `DROP DATABASE IF EXISTS \`${db}\`;`;
|
||||
|
||||
const map = {
|
||||
full_setup: `-- 1. Crear base de datos\n${createDb}\n\n-- 2. Crear usuario\n${createUser}\n\n-- 3. Dar permisos totales\n${grant}`,
|
||||
create_db: createDb,
|
||||
create_user: createUser,
|
||||
grant: grant,
|
||||
revoke: revoke,
|
||||
show_grants: showGrants,
|
||||
drop_user: dropUser,
|
||||
drop_db: dropDb,
|
||||
};
|
||||
|
||||
this.sqlText = map[this.dbHelper.op] || '';
|
||||
document.getElementById('sql-editor')?.focus();
|
||||
},
|
||||
|
||||
clearEditor() { this.sqlText = ''; this.results = []; this.columns = []; this.statusMsg = ''; },
|
||||
|
||||
nullStr(v) { return v === null || v === undefined ? 'NULL' : String(v); },
|
||||
|
||||
Reference in New Issue
Block a user