From cce71a095ca4e25a8486a886b23932fee797840b Mon Sep 17 00:00:00 2001 From: Mikhail Chusavitin Date: Wed, 21 Jan 2026 18:52:17 +0300 Subject: [PATCH] SQL comments for rows used now in tolltips --- public/app.js | 53 ++++++++++++++++++++++++++++++++++++++++----- public/index.html | 21 ++++++++++++++++++ src/MetaService.php | 9 +++++--- 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/public/app.js b/public/app.js index 74ed042..58be14d 100644 --- a/public/app.js +++ b/public/app.js @@ -185,6 +185,7 @@ async function loadTree() { treeEl.style.color = 'red'; } } +// selectTable async function selectTable(schema, tableName) { console.log('🔄 SELECTTABLE ВЫЗВАН - ВЕРСИЯ 3.0:', schema, '.', tableName); @@ -232,7 +233,7 @@ async function selectTable(schema, tableName) { } // ✅ Формируем колонки с правильными редакторами - const columns = [ + const columns = [ { formatter: "rowSelection", titleFormatter: "rowSelection", @@ -248,7 +249,32 @@ async function selectTable(schema, tableName) { const colDef = { title: col.COLUMN_NAME, field: col.COLUMN_NAME, - headerFilter: "input" + headerFilter: "input", + // ✅ Добавляем тултип для заголовка + headerTooltip: function(e, column) { + const comment = col.COLUMN_COMMENT; + if (comment) { + let tooltip = `${col.COLUMN_NAME}
`; + tooltip += `Тип: ${col.COLUMN_TYPE}
`; + tooltip += `${comment}`; + + if (col.IS_FOREIGN_KEY) { + tooltip += `
→ ${col.FOREIGN_KEY.ref_table}.${col.FOREIGN_KEY.ref_column}`; + } + + return tooltip; + } else { + // Если нет комментария - показываем базовую инфу + let tooltip = `${col.COLUMN_NAME}
`; + tooltip += `Тип: ${col.COLUMN_TYPE}`; + + if (col.IS_FOREIGN_KEY) { + tooltip += `
→ ${col.FOREIGN_KEY.ref_table}.${col.FOREIGN_KEY.ref_column}`; + } + + return tooltip; + } + } }; // ✅ Выбираем редактор в зависимости от типа поля @@ -634,6 +660,7 @@ document.getElementById('btnInsert').addEventListener('click', async () => { data_type: col.DATA_TYPE, is_fk: col.IS_FOREIGN_KEY, fk_info: col.FOREIGN_KEY + comment: col.COLUMN_COMMENT || '' // ✅ Добавлен комментарий }); } else { // Опциональное поле @@ -822,27 +849,40 @@ async function promptForRequiredFields(requiredFields, optionalFields) { }); } +// ✅ Рендерит input для поля // ✅ Рендерит input для поля function renderFieldInput(field, fkOptions, isRequired) { const requiredMark = isRequired ? '*' : ''; let fkInfo = ''; + let commentInfo = ''; + // ✅ Информация о FK if (field.is_fk && field.fk_info) { fkInfo = ` (→ ${field.fk_info.ref_table}.${field.fk_info.ref_column}) `; } + // ✅ Комментарий из БД + if (field.comment) { + commentInfo = ` +
+ 💡 ${escapeHtml(field.comment)} +
+ `; + } + let html = `
+ ${commentInfo} `; // FK поле с выпадающим списком if (field.is_fk && fkOptions[field.name]?.length > 0) { - html += ``; if (!isRequired) { html += ''; } else { @@ -858,7 +898,7 @@ function renderFieldInput(field, fkOptions, isRequired) { const placeholder = isRequired ? 'Введите число' : 'Оставьте пустым для NULL'; html += ` `; } @@ -868,7 +908,7 @@ function renderFieldInput(field, fkOptions, isRequired) { const placeholder = isRequired ? '' : 'Оставьте пустым для NULL'; html += ` `; } @@ -877,7 +917,7 @@ function renderFieldInput(field, fkOptions, isRequired) { const placeholder = isRequired ? 'Введите значение' : 'Оставьте пустым для NULL'; html += ` `; } @@ -886,6 +926,7 @@ function renderFieldInput(field, fkOptions, isRequired) { return html; } + // ✅ Конвертирует значение поля в правильный тип function convertFieldValue(value, editorType, dataType) { if (value === null || value === '') { diff --git a/public/index.html b/public/index.html index 19de8b2..a89eb32 100644 --- a/public/index.html +++ b/public/index.html @@ -159,6 +159,27 @@ background: #ccc; margin: 0 4px; } + /* Стили для тултипов */ + .tabulator-tooltip { + max-width: 400px; + padding: 8px 12px; + background: #333; + color: white; + border-radius: 4px; + font-size: 13px; + line-height: 1.5; + box-shadow: 0 2px 8px rgba(0,0,0,0.3); + } + + .tabulator-tooltip strong { + color: #4CAF50; + } + + .tabulator-tooltip em { + color: #b3e5fc; + font-style: normal; + } + diff --git a/src/MetaService.php b/src/MetaService.php index cee2976..2401266 100644 --- a/src/MetaService.php +++ b/src/MetaService.php @@ -33,7 +33,8 @@ class MetaService $sql = " SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE, COLUMN_KEY, - IS_NULLABLE, COLUMN_DEFAULT, EXTRA, ORDINAL_POSITION + IS_NULLABLE, COLUMN_DEFAULT, EXTRA, ORDINAL_POSITION, + COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :table ORDER BY ORDINAL_POSITION @@ -91,13 +92,14 @@ class MetaService 'DATA_TYPE' => $c['DATA_TYPE'], 'COLUMN_TYPE' => $c['COLUMN_TYPE'], 'COLUMN_KEY' => $c['COLUMN_KEY'], - 'IS_NULLABLE' => $isNullable, // ✅ Boolean, не строка + 'IS_NULLABLE' => $isNullable, 'COLUMN_DEFAULT' => $c['COLUMN_DEFAULT'], 'HAS_DEFAULT' => $hasDefault, 'EXTRA' => $c['EXTRA'], + 'COLUMN_COMMENT' => $c['COLUMN_COMMENT'] ?? '', // ✅ Добавлен комментарий 'IS_AUTO_INCREMENT' => str_contains($c['EXTRA'] ?? '', 'auto_increment'), 'ORDINAL_POSITION' => (int)$c['ORDINAL_POSITION'], - 'IS_REQUIRED' => !$isNullable && !$hasDefault && !str_contains($c['EXTRA'] ?? '', 'auto_increment'), // ✅ Правильная логика + 'IS_REQUIRED' => !$isNullable && !$hasDefault && !str_contains($c['EXTRA'] ?? '', 'auto_increment'), 'EDITOR_TYPE' => $this->getEditorType($c), 'IS_FOREIGN_KEY' => isset($fkMap[$name]), 'FOREIGN_KEY' => $fkMap[$name] ?? null @@ -113,6 +115,7 @@ class MetaService ]; } + private function getEditorType(array $col): string { $type = strtolower($col['DATA_TYPE']);