v0.319.0: the app page in panels, the login in one place, a password the box never had is said in words
gates / gates (push) Successful in 52s
gates / gates (push) Successful in 52s
- style A (operator 2026-10-16): hero, tab bar and every section are panels on --bg-1, one width, 16px apart; the install page's form groups use the same rule; the settings tab's 700px inner wrapper is gone - „Belépés az alkalmazásba": name + password side by side, fetched on demand (R-254, R-709); pairing in app_login.go - the empty-value rule: no stored value -> a sentence, never an eye; page and reveal endpoint share storedValuePresent - „Cím és kulcsok" is rows (no Domain input, no disabled storage select, no install form); hint under the title - tests red-proved: app_page_tuning_test.go (4); 36 app-page parity fixtures re-captured, 4 new; install fixtures unchanged Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
„Adatok es mentes" holds everything about the FILES, including the backup card that used to
|
||||
sit on this page. */}}
|
||||
|
||||
<div class="deploy-container">
|
||||
<div class="app-settings-tab">
|
||||
{{if .FlashSuccess}}<div class="flash flash-success">{{.FlashSuccess}}</div>{{end}}
|
||||
{{if .FlashError}}<div class="flash flash-error">{{.FlashError}}</div>{{end}}
|
||||
|
||||
@@ -62,13 +62,13 @@
|
||||
|
||||
{{/* 3. THE REST OF WHAT THE APP WANTS FROM THE HOUSEHOLD. */}}
|
||||
{{- if .InstallHoldClosed}}
|
||||
<div class="app-section" style="margin-top:1rem" id="install-hold-card">
|
||||
<div class="app-section" id="install-hold-card">
|
||||
<h3>{{T "app_info.install_hold_title"}}</h3>
|
||||
<p>{{T "app_info.install_hold_closed"}}</p>
|
||||
</div>
|
||||
{{- end}}
|
||||
{{- if .SetupGateClosed}}
|
||||
<div class="app-section" style="margin-top:1rem" id="setup-gate-card">
|
||||
<div class="app-section" id="setup-gate-card">
|
||||
<h3>{{T "app_info.setup_gate_title"}}</h3>
|
||||
<p>{{T "app_info.setup_gate_closed"}}</p>{{- if .SignupNative}}
|
||||
<p class="form-hint" data-restarts-once="true">{{T "app_info.restarts_once"}}</p>{{- end}}
|
||||
@@ -84,7 +84,7 @@
|
||||
{{- end}}
|
||||
|
||||
{{- if .CloseSignupOffered}}
|
||||
<div class="app-section" style="margin-top:1rem" id="close-signup-card">
|
||||
<div class="app-section" id="close-signup-card">
|
||||
<h3>{{T "app_info.signup_title"}}</h3>
|
||||
<p>{{T "app_info.close_signup_text"}}</p>{{- if .SignupNative}}
|
||||
<p class="form-hint" data-restarts-once="true">{{T "app_info.restarts_once"}}</p>{{- end}}
|
||||
@@ -93,7 +93,7 @@
|
||||
</div>
|
||||
{{- end}}
|
||||
{{- if or .SignupClosed .SignupOpenUntil}}
|
||||
<div class="app-section" style="margin-top:1rem" id="signup-card">
|
||||
<div class="app-section" id="signup-card">
|
||||
<h3>{{T "app_info.signup_title"}}</h3>
|
||||
{{- if .SignupOpenUntil}}
|
||||
<p>{{T "app_info.signup_open_until"}} {{.SignupOpenUntil}}</p>
|
||||
@@ -121,6 +121,35 @@
|
||||
|
||||
{{/* The logins, each already its own guarded card on the details page. */}}
|
||||
<div class="app-sections">
|
||||
{{/* v0.319.0 — „BELEPES AZ ALKALMAZASBA": the name and the password of the app's first login,
|
||||
side by side. The values are fetched on demand (R-254, R-709); the page learns only whether
|
||||
the box holds one (app_login.go), and a field it holds none for is a sentence, not an eye. */}}
|
||||
{{if .LoginFields}}
|
||||
<div class="app-section" id="app-login-panel" data-login-panel="1">
|
||||
<h3>{{T "app_page.login_title"}}</h3>
|
||||
<p>{{T "app_page.login_desc"}}</p>
|
||||
<div class="app-login-pair">
|
||||
{{- range .LoginFields}}
|
||||
<div class="app-login-field" data-login-field="{{.EnvVar}}">
|
||||
<label class="app-login-label" for="field-{{.EnvVar}}">{{.Label}}</label>
|
||||
{{- if .Restored}}
|
||||
<p class="form-hint" data-login-restored="{{.EnvVar}}">{{T "deploy.login_from_backup"}}</p>
|
||||
{{- else if not .Stored}}
|
||||
<p class="form-hint" data-login-not-stored="{{.EnvVar}}">{{if .IsName}}{{T "app_page.login_no_name"}}{{else}}{{T "app_page.login_no_password"}}{{end}}</p>
|
||||
{{- else if .OnDemand}}
|
||||
<div class="input-with-button">
|
||||
<input type="password" id="field-{{.EnvVar}}" class="form-control" value="" placeholder="••••••••••••" readonly>
|
||||
<button type="button" class="btn btn-sm btn-outline" data-login-reveal="{{.EnvVar}}" onclick="revealAutoField('{{$.Stack.Name}}','{{.EnvVar}}', this, 'field-{{.EnvVar}}')">{{T "deploy.megjelenites"}}</button>
|
||||
</div>
|
||||
{{- else}}
|
||||
<input type="text" id="field-{{.EnvVar}}" class="form-control" value="{{.Value}}" readonly>
|
||||
{{- end}}
|
||||
</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .InitialCreds}}
|
||||
<div class="app-section">
|
||||
<h3>{{T "app_info.kezdeti_belepesi_adatok"}}</h3>
|
||||
@@ -173,8 +202,8 @@
|
||||
household reached by pressing „Beallitasok" on an installed app. The hint lives with the
|
||||
fields it is about, at the bottom of this tab. */}}
|
||||
{{if .StorageInfo}}
|
||||
<div class="deploy-storage-info">
|
||||
<h4>{{T "deploy.adattarolas"}}</h4>
|
||||
<div class="app-section">
|
||||
<h3>{{T "deploy.adattarolas"}}</h3>
|
||||
<div class="settings-grid">
|
||||
<div class="settings-row">
|
||||
<span class="settings-label">{{T "deploy.tarhely"}}</span>
|
||||
@@ -201,8 +230,8 @@
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .StaleData}}
|
||||
<div class="deploy-stale-data">
|
||||
<h4>{{T "deploy.korabbi_adatok"}}</h4>
|
||||
<div class="app-section deploy-stale-data">
|
||||
<h3>{{T "deploy.korabbi_adatok"}}</h3>
|
||||
<p class="form-hint" style="margin-bottom:1rem">
|
||||
{{T "deploy.az_alkalmazas_adatainak_masolata_megtala"}}
|
||||
</p>
|
||||
@@ -230,7 +259,7 @@
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .HasIntegrations}}
|
||||
<div class="app-optional-config">
|
||||
<div class="app-section">
|
||||
<h3>{{T "deploy.integraciok"}}</h3>
|
||||
<p class="config-group-desc">
|
||||
{{T "deploy.mas_telepitett_alkalmazasokkal_valo_ossz"}}
|
||||
@@ -290,7 +319,7 @@
|
||||
{{end}}
|
||||
|
||||
{{if .GeoGlobalEnabled}}
|
||||
<div class="app-optional-config">
|
||||
<div class="app-section">
|
||||
<h3>{{T "deploy.foldrajzi_korlatozas"}}</h3>
|
||||
<p class="config-group-desc">
|
||||
{{T "deploy.az_alkalmazas_egyeni_orszagkorlatozas_ne"}}
|
||||
@@ -425,7 +454,7 @@
|
||||
{{end}}
|
||||
|
||||
{{if .HasOptionalConfig}}
|
||||
<div class="app-optional-config">
|
||||
<div class="app-section">
|
||||
<h3>{{T "deploy.opcionalis_beallitasok"}}</h3>
|
||||
{{range .OptionalConfig}}
|
||||
<div class="config-group">
|
||||
@@ -519,7 +548,7 @@
|
||||
{{end}}
|
||||
|
||||
{{if .AppEmailSupported}}
|
||||
<div class="app-optional-config">
|
||||
<div class="app-section">
|
||||
<h3>{{T "deploy.email_kuldes"}}</h3>
|
||||
<p class="config-group-desc">
|
||||
{{T "deploy.ez_az_alkalmazas_tud_emailt"}}
|
||||
@@ -542,18 +571,38 @@
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="app-section">
|
||||
{{/* „CIM ES KULCSOK" (v0.319.0) — what was set at install, as rows. The hint that says they
|
||||
cannot be changed sits under the title it is about, not at the bottom of the tab. The domain,
|
||||
the subdomain and the data folder are the „Cim" and „Tarhely" rows; the login is the panel
|
||||
above; everything else is a row here (app_login.go appSettingRows). */}}
|
||||
<div class="app-section" data-address-keys="1">
|
||||
<h3>{{T "app_page.address_and_keys"}}</h3>
|
||||
<p class="app-field-hint" data-readonly-hint="1">{{T "app_page.installed_readonly"}}</p>
|
||||
{{if .EffectiveSubdomain}}
|
||||
<div class="app-field-row">
|
||||
<div class="app-field-label">{{T "app_page.address"}}</div>
|
||||
<div class="app-field-value" data-app-address-row="1">{{.EffectiveSubdomain}}.{{.Domain}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<form id="deploy-form" class="deploy-form">
|
||||
{{template "app_deploy_fields" .}}
|
||||
</form>
|
||||
<p class="app-field-hint" data-readonly-hint="1">{{T "app_page.installed_readonly"}}</p>
|
||||
{{if .CurrentHDDPath}}
|
||||
<div class="app-field-row">
|
||||
<div class="app-field-label">{{T "deploy.tarhely"}}</div>
|
||||
<div class="app-field-value" data-app-storage-row="1">{{if .CurrentHDDPathMissing}}{{T "deploy.nem_elerheto"}}{{else if .CurrentHDDLabel}}{{.CurrentHDDLabel}}{{else}}<span class="mono">{{.CurrentHDDPath}}</span>{{end}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{- range .SettingsRows}}
|
||||
<div class="app-field-row" data-setting-row="{{.EnvVar}}">
|
||||
<div class="app-field-label">{{.Label}}</div>
|
||||
{{- if .OnDemand}}
|
||||
<div class="app-field-value input-with-button">
|
||||
<input type="password" id="auto-field-{{.EnvVar}}" class="form-control" value="" placeholder="••••••••••••" readonly aria-label="{{.Label}}">
|
||||
<button type="button" class="btn btn-sm btn-outline" onclick="revealAutoField('{{$.Stack.Name}}','{{.EnvVar}}', this)">{{T "deploy.megjelenites"}}</button>
|
||||
</div>
|
||||
{{- else}}
|
||||
<div class="app-field-value">{{.Value}}</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -612,46 +661,9 @@ function icCopyPw(btn) {
|
||||
|
||||
{{template "app_press_script" .}}
|
||||
<script>
|
||||
function checkStorageSpace(sel) {
|
||||
var opt = sel.options[sel.selectedIndex];
|
||||
var warn = document.getElementById('storage-space-warn');
|
||||
if (!warn) return;
|
||||
var freePct = parseFloat(opt.getAttribute('data-free-percent') || '100');
|
||||
warn.style.display = freePct < 20 ? 'block' : 'none';
|
||||
}
|
||||
// Check on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var sel = document.querySelector('select[onchange="checkStorageSpace(this)"]');
|
||||
if (sel) checkStorageSpace(sel);
|
||||
});
|
||||
|
||||
// R-254 site two: on an already-deployed app the value is NOT in this page — it is fetched on
|
||||
// demand, and the server records the act. Nothing caches it between presses.
|
||||
// R-709 (v0.280.0): an installed app's `type: password` value, fetched on demand like a secret.
|
||||
function revealPasswordField(stackName, envVar, btn) {
|
||||
var el = document.getElementById('field-' + envVar);
|
||||
if (!el) return;
|
||||
if (btn.dataset.shown === '1') {
|
||||
el.value = '';
|
||||
el.type = 'password';
|
||||
btn.dataset.shown = '';
|
||||
return;
|
||||
}
|
||||
btn.disabled = true;
|
||||
fetch('/stacks/' + encodeURIComponent(stackName) + '/auto-field/reveal', {
|
||||
method: 'POST',
|
||||
headers: Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, csrfHeaders()),
|
||||
credentials: 'same-origin',
|
||||
body: 'env_var=' + encodeURIComponent(envVar)
|
||||
}).then(function (r) { return r.json(); }).then(function (j) {
|
||||
btn.disabled = false;
|
||||
if (!j.ok) { showAlert(j.error || '{{T "deploy.a_lekeres_nem_sikerult"}}'); return; }
|
||||
el.value = j.data.value;
|
||||
el.type = 'text';
|
||||
el.dataset.revealed = '1';
|
||||
btn.dataset.shown = '1';
|
||||
}).catch(function () { btn.disabled = false; showAlert('{{T "deploy.a_lekeres_nem_sikerult"}}'); });
|
||||
}
|
||||
// R-254 site two: on an already-deployed app no secret is in this page — it is fetched on demand,
|
||||
// and the server records the act. Nothing caches it between presses. Since v0.319.0 the login
|
||||
// panel's name and password use this too (R-709: a `type: password` value, fetched like a secret).
|
||||
function revealAutoField(stackName, envVar, btn, elId) {
|
||||
var el = document.getElementById(elId || ('auto-field-' + envVar));
|
||||
if (!el) return;
|
||||
|
||||
Reference in New Issue
Block a user