d170a2aecf
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
188 lines
12 KiB
HTML
188 lines
12 KiB
HTML
{{/* THE APP'S CONFIGURATION FIELDS — the install wizard's form (deploy.html).
|
|
|
|
v0.319.0: the settings tab no longer renders this — it shows the install answers as rows and
|
|
the login as one panel (app_settings.html, app_login.go). The `.AlreadyDeployed` branches below
|
|
are NOT dead: `/apps/{slug}/install` still answers for an app that is installed, and renders
|
|
this form read-only. Their guards are what keep an installed app's secrets out of that page
|
|
(TestDeployPage_DeployedApp_DoesNotCarryTheSecret, TestR709_AnInstalledAppsPasswordIsNotInThePage)
|
|
and the parity case `deploy_installed` renders them.
|
|
|
|
The secret rules are unchanged and load-bearing:
|
|
R-254 — an INSTALLED app's `type: secret` value is not in the page; the eye fetches it.
|
|
R-709 — nor is a `type: password` one.
|
|
The PRE-DEPLOY hidden input is deliberate: the form must carry what it submits, so the value
|
|
saved is the one the household was shown (controller/README §318). */}}
|
|
|
|
{{define "app_deploy_fields"}}
|
|
{{if .AutoFields}}
|
|
<div class="form-section">
|
|
<h4>{{T "deploy.automatikusan_generalt_ertekek"}}</h4>
|
|
{{if .AlreadyDeployed}}
|
|
<p class="form-section-desc">{{T "deploy.ezek_az_ertekek_automatikusan_jottek"}}</p>
|
|
{{else}}
|
|
<p class="form-section-desc">{{T "deploy.ezek_az_ertekek_a_telepitessel"}}</p>
|
|
{{end}}
|
|
{{$autoValues := .AutoFieldValues}}
|
|
{{$stackName := .Stack.Name}}
|
|
{{$isDeployed := .AlreadyDeployed}}
|
|
{{range .AutoFields}}
|
|
{{$val := index $autoValues .EnvVar}}
|
|
<div class="form-group form-group-auto">
|
|
<label>{{.Label}} {{if eq .Type "secret"}}<span class="auto-generated-badge"><svg class="ico ico-sm"><use href="#i-check"/></svg> {{T "deploy.automatikusan_generalva"}}</span>{{end}}</label>
|
|
{{if $val}}
|
|
{{if eq .Type "secret"}}
|
|
{{if $isDeployed}}
|
|
<!-- R-254 site two: on an ALREADY-DEPLOYED app nothing is being submitted, so there is
|
|
no reason for the value to be in this page at all. It is fetched on demand. The
|
|
pre-deploy branch below is different and deliberate — the form must carry what it
|
|
submits, so the saved value is the one the customer was shown (README §318). -->
|
|
<div class="input-with-button">
|
|
<input type="password" id="auto-field-{{.EnvVar}}" class="form-control" value="" placeholder="••••••••••••" readonly>
|
|
<button type="button" class="btn btn-sm btn-outline" onclick="revealAutoField('{{$stackName}}','{{.EnvVar}}', this)">{{T "deploy.megjelenites"}}</button>
|
|
</div>
|
|
{{else}}
|
|
<div class="input-with-button">
|
|
<input type="password" id="auto-field-{{.EnvVar}}" class="form-control" value="{{$val}}" readonly>
|
|
<button type="button" class="btn btn-sm btn-outline" onclick="toggleAutoField('auto-field-{{.EnvVar}}', this)">{{T "deploy.megjelenites"}}</button>
|
|
</div>
|
|
{{end}}
|
|
{{else}}
|
|
<input type="text" id="auto-field-{{.EnvVar}}" class="form-control" value="{{$val}}" readonly>
|
|
{{end}}
|
|
{{if and (not $isDeployed) (eq .Type "secret")}}
|
|
<input type="hidden" name="{{.EnvVar}}" value="{{$val}}">
|
|
{{end}}
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .UserFields}}
|
|
<div class="form-section">
|
|
<h4>{{T "deploy.beallitasok"}}</h4>
|
|
{{range .UserFields}}
|
|
{{/* v0.316.0: an INSTALLED app shows its address once, as the „Cim" row above these
|
|
fields, so the disabled subdomain input saying the same thing is skipped. The
|
|
install wizard still asks for it — this is the read-only view's duplicate only. */}}
|
|
{{if and $.AlreadyDeployed (eq .Type "subdomain")}}{{continue}}{{end}}
|
|
<div class="form-group">
|
|
<label for="field-{{.EnvVar}}">
|
|
{{.Label}}
|
|
{{if or .Required (eq .Type "password")}}<span class="required">*</span>{{end}}
|
|
{{if .LockedAfterDeploy}}<span class="locked-hint">{{T "deploy.telepites_utan_nem_modosithato"}}</span>{{end}}
|
|
</label>
|
|
|
|
{{if eq .Type "subdomain"}}
|
|
<div class="subdomain-input-group">
|
|
<input type="text" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
|
class="form-control subdomain-input"
|
|
{{/* R-351: a reinstall offers the address the customer's own backup recorded,
|
|
ahead of the catalog default. Editable — a domain can legitimately change. */}}
|
|
value="{{if and $.AlreadyDeployed $.DeployedFieldValues}}{{index $.DeployedFieldValues .EnvVar}}{{else if index $.RestoreFieldValues .EnvVar}}{{index $.RestoreFieldValues .EnvVar}}{{else}}{{.Default}}{{end}}"
|
|
placeholder="{{T "deploy.aldomain_placeholder"}}"
|
|
pattern="[a-z0-9]([a-z0-9-]*[a-z0-9])?"
|
|
required
|
|
{{if $.AlreadyDeployed}}disabled{{end}}
|
|
oninput="this.value=this.value.toLowerCase().replace(/[^a-z0-9-]/g,'')">
|
|
<span class="subdomain-suffix">.{{$.Domain}}</span>
|
|
</div>
|
|
{{if not $.AlreadyDeployed}}
|
|
<span class="form-hint">{{T "deploy.az_aldomain_telepites_utan_nem"}}</span>
|
|
{{end}}
|
|
{{else if eq .Type "select"}}
|
|
<select id="field-{{.EnvVar}}" name="{{.EnvVar}}" class="form-control"
|
|
{{if $.AlreadyDeployed}}disabled{{end}}>
|
|
{{range .Options}}
|
|
<option value="{{.Value}}">{{.Label}}</option>
|
|
{{end}}
|
|
</select>
|
|
{{else if eq .Type "password"}}
|
|
<div class="input-with-button">
|
|
{{- if $.AlreadyDeployed}}
|
|
{{- /* R-709 (v0.280.0): an installed app's password is never in this page; the eye fetches it. */}}
|
|
<input type="password" id="field-{{.EnvVar}}" class="form-control" value="" placeholder="••••••••••••" disabled>
|
|
{{- if not (and $.RestoredLogins (index $.RestoredLogins .EnvVar))}}
|
|
<button type="button" class="btn btn-sm btn-outline pw-toggle-btn"
|
|
onclick="revealPasswordField('{{$.Stack.Name}}', '{{.EnvVar}}', this)"
|
|
title="{{T "deploy.megjelenites"}}">👁</button>
|
|
{{- end}}
|
|
{{- else}}
|
|
<input type="password" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
|
class="form-control" value="{{.Default}}"
|
|
placeholder="{{.Placeholder}}"
|
|
data-field-type="password"
|
|
required>
|
|
<button type="button" class="btn btn-sm btn-outline pw-toggle-btn"
|
|
onclick="togglePasswordField('field-{{.EnvVar}}', 'field-confirm-{{.EnvVar}}', this)"
|
|
title="{{T "deploy.megjelenites"}}">👁</button>
|
|
<button type="button" class="btn btn-sm btn-outline"
|
|
onclick="generatePassword('field-{{.EnvVar}}', 'field-confirm-{{.EnvVar}}', '{{.Generate}}')">{{T "deploy.generalas"}}</button>
|
|
{{- end}}
|
|
</div>
|
|
{{if $.AlreadyDeployed}}
|
|
<span class="form-hint">{{if and $.RestoredLogins (index $.RestoredLogins .EnvVar)}}{{T "deploy.login_from_backup"}}{{else}}{{T "deploy.telepiteskor_beallitott_kezdeti_jelszo_h"}}{{end}}</span>
|
|
{{else}}
|
|
<div class="input-with-button" style="margin-top:.25rem">
|
|
<input type="password" id="field-confirm-{{.EnvVar}}"
|
|
class="form-control" placeholder="{{T "deploy.jelszo_megerositese"}}"
|
|
data-confirm-for="field-{{.EnvVar}}">
|
|
</div>
|
|
{{end}}
|
|
{{else if eq .Type "boolean"}}
|
|
<label class="toggle">
|
|
<input type="checkbox" id="field-{{.EnvVar}}" name="{{.EnvVar}}" value="true"
|
|
{{if $.AlreadyDeployed}}disabled{{end}}>
|
|
<span class="toggle-label">{{T "deploy.igen"}}</span>
|
|
</label>
|
|
{{else if eq .Type "path"}}
|
|
{{if $.StoragePaths}}
|
|
<select id="field-{{.EnvVar}}" name="{{.EnvVar}}" class="form-control"
|
|
{{if $.AlreadyDeployed}}disabled{{end}}
|
|
onchange="checkStorageSpace(this)">
|
|
{{range $.StoragePaths}}
|
|
<option value="{{.Path}}" data-free-percent="{{printf "%.0f" .FreePercent}}"
|
|
{{if .NotAllowed}}disabled{{end}}
|
|
{{/* R-351: on a reinstall the drive the BACKUP recorded wins over the
|
|
configured default — it is where this app's data actually lived, and
|
|
restoring into a different drive is the mismatch the restore then has
|
|
to stop and name. The customer can still pick another. */}}
|
|
{{if $.AlreadyDeployed}}{{if eq .Path $.CurrentHDDPath}}selected{{end}}{{else if $.RestorePrefillHDDPath}}{{if and (eq .Path $.RestorePrefillHDDPath) (not .NotAllowed)}}selected{{end}}{{else if and .IsDefault (not .NotAllowed)}}selected{{end}}>
|
|
{{T "deploy.szabad_2"}}{{if .NotAllowed}} ({{.NotAllowedNote}}){{else if .IsDefault}} {{T "deploy.alapertelmezett"}}{{end}}
|
|
</option>
|
|
{{end}}
|
|
{{if $.CurrentHDDPathMissing}}
|
|
<option value="{{$.CurrentHDDPath}}" selected disabled>{{T "deploy.nem_elerheto"}}</option>
|
|
{{end}}
|
|
</select>
|
|
<div id="storage-space-warn" class="form-hint" style="color:var(--warn);display:none">
|
|
<svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg> {{T "deploy.a_kivalasztott_tarhely_majdnem_megtelt"}}
|
|
</div>
|
|
<div class="form-hint" style="margin-top:.4rem;opacity:.8">
|
|
<svg class="ico ico-sm"><use href="#i-info"/></svg> {{T "deploy.a_kivalasztott_meghajton_az_alkalmazas"}}
|
|
</div>
|
|
{{else}}
|
|
<input type="text" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
|
class="form-control" value="{{.Default}}"
|
|
placeholder="{{.Placeholder}}"
|
|
{{if .Required}}required{{end}}
|
|
{{if $.AlreadyDeployed}}disabled{{end}}>
|
|
<span class="form-hint" style="color:var(--warn)">{{T "deploy.nincs_regisztralt_adattarolo_adja_meg"}}</span>
|
|
{{end}}
|
|
{{else}}
|
|
<input type="text" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
|
class="form-control" value="{{.Default}}"
|
|
placeholder="{{.Placeholder}}"
|
|
{{if .Required}}required{{end}}
|
|
{{if $.AlreadyDeployed}}disabled{{end}}>
|
|
{{end}}
|
|
|
|
{{if and .Description (ne .Type "subdomain")}}
|
|
<span class="form-hint">{{.Description}}</span>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|