Add Adminer login hint

This commit is contained in:
2026-08-05 22:26:37 +02:00
parent 4777bda0b2
commit 1d6837223b
6 changed files with 43 additions and 1 deletions
+1
View File
@@ -107,6 +107,7 @@ There are three selectable data sources:
- Supplier/manufacturer website settings such as source URL, search templates, fallback mode, browser engine, headless mode, wait time, notes and enabled/priority flags belong in Local scrape DB, not in the product catalog database. - Supplier/manufacturer website settings such as source URL, search templates, fallback mode, browser engine, headless mode, wait time, notes and enabled/priority flags belong in Local scrape DB, not in the product catalog database.
- The Settings modal should expose an `Open Adminer` action beside `Local scrape DB`; it opens the local Adminer URL from `ADMINER_URL` / `databaseTool.url` for inspecting local MariaDB databases. - The Settings modal should expose an `Open Adminer` action beside `Local scrape DB`; it opens the local Adminer URL from `ADMINER_URL` / `databaseTool.url` for inspecting local MariaDB databases.
- Start Adminer only through `npm run adminer`; the script downloads the ignored local `tools/adminer/adminer.php` file when missing and runs it on the configured local Adminer URL. Adminer requires local PHP CLI. - Start Adminer only through `npm run adminer`; the script downloads the ignored local `tools/adminer/adminer.php` file when missing and runs it on the configured local Adminer URL. Adminer requires local PHP CLI.
- Adminer login help may show non-secret local connection fields such as system, host, port, database and user, but must never render or print the actual password. Show password source as `.env DB_PASSWORD` instead.
- It must never be used as a fallback for catalog reads. When selected in the UI, existing catalog reads continue using Local 9bplus DB until dedicated scrape-storage endpoints are added. - It must never be used as a fallback for catalog reads. When selected in the UI, existing catalog reads continue using Local 9bplus DB until dedicated scrape-storage endpoints are added.
- The schema is versioned in `sql/local-scrape-db.sql` and can be created with `npm run db:create-scrape`. - The schema is versioned in `sql/local-scrape-db.sql` and can be created with `npm run db:create-scrape`.
- Existing legacy mapping rows from `Local 9bplus DB` can be copied into Local scrape DB with `npm run db:migrate-mapping-to-scrape`. - Existing legacy mapping rows from `Local 9bplus DB` can be copied into Local scrape DB with `npm run db:migrate-mapping-to-scrape`.
+14
View File
@@ -51,6 +51,9 @@ const localDbInputs = document.querySelectorAll("#localDbFields input");
const testLocalDbButton = document.querySelector("#testLocalDbButton"); const testLocalDbButton = document.querySelector("#testLocalDbButton");
const localDbTestResult = document.querySelector("#localDbTestResult"); const localDbTestResult = document.querySelector("#localDbTestResult");
const openDbGateButton = document.querySelector("#openDbGateButton"); const openDbGateButton = document.querySelector("#openDbGateButton");
const adminerServerValue = document.querySelector("#adminerServerValue");
const adminerUserValue = document.querySelector("#adminerUserValue");
const adminerDatabaseValue = document.querySelector("#adminerDatabaseValue");
const lightContrastSelect = document.querySelector("#lightContrastSelect"); const lightContrastSelect = document.querySelector("#lightContrastSelect");
const darkContrastSelect = document.querySelector("#darkContrastSelect"); const darkContrastSelect = document.querySelector("#darkContrastSelect");
const catalogScreen = document.querySelector(".catalog-screen"); const catalogScreen = document.querySelector(".catalog-screen");
@@ -1012,6 +1015,7 @@ function loadDatabaseMode() {
} }
syncDatabasePermissions(mode); syncDatabasePermissions(mode);
syncLocalDbFields(mode); syncLocalDbFields(mode);
syncAdminerLoginHint();
renderDatabaseModeNote(mode); renderDatabaseModeNote(mode);
refreshDatabaseStatusLabel(); refreshDatabaseStatusLabel();
} }
@@ -1029,6 +1033,16 @@ function saveLocalDbSettings() {
for (const input of localDbInputs) for (const input of localDbInputs)
settings[input.id] = input.value; settings[input.id] = input.value;
localStorage.setItem("catalog-maker:local-db-settings", JSON.stringify(settings)); localStorage.setItem("catalog-maker:local-db-settings", JSON.stringify(settings));
syncAdminerLoginHint();
}
function syncAdminerLoginHint() {
const host = document.querySelector("#localDbHost")?.value || "127.0.0.1";
const port = document.querySelector("#localDbPort")?.value || "3306";
const user = document.querySelector("#localDbUser")?.value || "root";
const catalogDb = document.querySelector("#localDbName")?.value || "9bplus";
adminerServerValue.textContent = `${host}:${port}`;
adminerUserValue.textContent = user;
adminerDatabaseValue.textContent = `${catalogDb} / catalog_scrape`;
} }
async function testLocalDbConnection() { async function testLocalDbConnection() {
saveLocalDbSettings(); saveLocalDbSettings();
+15
View File
@@ -51,6 +51,9 @@ const localDbInputs = document.querySelectorAll("#localDbFields input");
const testLocalDbButton = document.querySelector("#testLocalDbButton"); const testLocalDbButton = document.querySelector("#testLocalDbButton");
const localDbTestResult = document.querySelector("#localDbTestResult"); const localDbTestResult = document.querySelector("#localDbTestResult");
const openDbGateButton = document.querySelector("#openDbGateButton"); const openDbGateButton = document.querySelector("#openDbGateButton");
const adminerServerValue = document.querySelector("#adminerServerValue");
const adminerUserValue = document.querySelector("#adminerUserValue");
const adminerDatabaseValue = document.querySelector("#adminerDatabaseValue");
const lightContrastSelect = document.querySelector("#lightContrastSelect"); const lightContrastSelect = document.querySelector("#lightContrastSelect");
const darkContrastSelect = document.querySelector("#darkContrastSelect"); const darkContrastSelect = document.querySelector("#darkContrastSelect");
const catalogScreen = document.querySelector(".catalog-screen"); const catalogScreen = document.querySelector(".catalog-screen");
@@ -1105,6 +1108,7 @@ function loadDatabaseMode() {
} }
syncDatabasePermissions(mode); syncDatabasePermissions(mode);
syncLocalDbFields(mode); syncLocalDbFields(mode);
syncAdminerLoginHint();
renderDatabaseModeNote(mode); renderDatabaseModeNote(mode);
refreshDatabaseStatusLabel(); refreshDatabaseStatusLabel();
} }
@@ -1123,6 +1127,17 @@ function saveLocalDbSettings() {
const settings = {}; const settings = {};
for (const input of localDbInputs) settings[input.id] = input.value; for (const input of localDbInputs) settings[input.id] = input.value;
localStorage.setItem("catalog-maker:local-db-settings", JSON.stringify(settings)); localStorage.setItem("catalog-maker:local-db-settings", JSON.stringify(settings));
syncAdminerLoginHint();
}
function syncAdminerLoginHint() {
const host = document.querySelector("#localDbHost")?.value || "127.0.0.1";
const port = document.querySelector("#localDbPort")?.value || "3306";
const user = document.querySelector("#localDbUser")?.value || "root";
const catalogDb = document.querySelector("#localDbName")?.value || "9bplus";
adminerServerValue.textContent = `${host}:${port}`;
adminerUserValue.textContent = user;
adminerDatabaseValue.textContent = `${catalogDb} / catalog_scrape`;
} }
async function testLocalDbConnection() { async function testLocalDbConnection() {
+7
View File
@@ -205,6 +205,13 @@
<p class="settings-note" id="localDbTestResult">Connection not tested.</p> <p class="settings-note" id="localDbTestResult">Connection not tested.</p>
</div> </div>
<p class="settings-note" id="databaseModeNote">Local 9bplus database selected.</p> <p class="settings-note" id="databaseModeNote">Local 9bplus database selected.</p>
<div class="adminer-login-hint" id="adminerLoginHint" aria-label="Adminer login details">
<div class="adminer-login-row"><span>System</span><strong>MySQL</strong></div>
<div class="adminer-login-row"><span>Server</span><strong id="adminerServerValue">127.0.0.1:3306</strong></div>
<div class="adminer-login-row"><span>User</span><strong id="adminerUserValue">root</strong></div>
<div class="adminer-login-row"><span>Password</span><strong>DB_PASSWORD in .env</strong></div>
<div class="adminer-login-row"><span>Database</span><strong id="adminerDatabaseValue">9bplus / catalog_scrape</strong></div>
</div>
</fieldset> </fieldset>
<fieldset class="settings-group"> <fieldset class="settings-group">
+1 -1
View File
File diff suppressed because one or more lines are too long
+5
View File
@@ -205,6 +205,9 @@
.settings-select { @apply min-w-0 rounded border border-slate-300 bg-white px-1 py-1 text-[11px] text-slate-800; } .settings-select { @apply min-w-0 rounded border border-slate-300 bg-white px-1 py-1 text-[11px] text-slate-800; }
.settings-note, .settings-permissions { @apply m-0 text-[10px] leading-tight text-slate-500; } .settings-note, .settings-permissions { @apply m-0 text-[10px] leading-tight text-slate-500; }
.settings-permissions { @apply grid gap-0.5; } .settings-permissions { @apply grid gap-0.5; }
.adminer-login-hint { @apply mt-1 grid gap-0.5 rounded border border-slate-300 bg-slate-100 p-1.5 text-[10px] leading-tight text-slate-600; }
.adminer-login-row { @apply flex items-center justify-between gap-2; }
.adminer-login-row strong { @apply truncate text-right font-semibold text-slate-800; }
.connection-ok { @apply text-emerald-700; } .connection-ok { @apply text-emerald-700; }
.connection-error { @apply text-red-700; } .connection-error { @apply text-red-700; }
.suggested-row { @apply grid grid-cols-[40px_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 px-1 py-1 text-[11px]; } .suggested-row { @apply grid grid-cols-[40px_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 px-1 py-1 text-[11px]; }
@@ -340,6 +343,8 @@
html.dark .settings-field { @apply text-slate-100; } html.dark .settings-field { @apply text-slate-100; }
html.dark .settings-group { @apply border-slate-700; } html.dark .settings-group { @apply border-slate-700; }
html.dark .settings-field input { @apply border-slate-600 bg-slate-800 text-slate-100; } html.dark .settings-field input { @apply border-slate-600 bg-slate-800 text-slate-100; }
html.dark .adminer-login-hint { @apply border-slate-700 bg-slate-800 text-slate-400; }
html.dark .adminer-login-row strong { @apply text-slate-100; }
html.dark .modal-close, html.dark .modal-close,
html.dark .settings-test-button, html.dark .settings-test-button,
html.dark .settings-inline-button, html.dark .settings-inline-button,