Files
felhom-controller/controller/internal/web/templates/app_guide.html
T
admin f30a80841e
gates / gates (push) Successful in 50s
v0.320.0: FileBrowser is part of the box again; every app says where its login is; a „Fájlok" button
FileBrowser (and traefik, cloudflared, samba) has no app.yaml, so Deployed is false. Since v0.315.0 the
app page read Deployed alone and showed FileBrowser "not installed", with Install and without its login.
A protected infra stack is now installed by definition on the app page (Deployed || Protected, as every
other surface already counted): settings/guide/log tabs, Restart only, no install page, no data tab.
The Install press would have deployed the infra stack as an app: DeployStack and the deploy API now
refuse a protected stack.

In the operator state (the box does not know FileBrowser's password - both demo boxes) the login panel
offers "Új jelszó beállítása": the file browser's own CLI with the server stopped (spiked on demo-hp:
new 200, old 401, users/shares/settings unchanged), verified, stored encrypted, state generated.

Every installed app's settings tab has the login panel with exactly one answer: the box's fields, the
login the app wrote (InitialCreds), or a sentence chosen by the catalog's new app_info.login_kind
(first_visit default, email, none; none behind the family gate says the family sign-in is the login).

"Fájlok ↗" opens the library folder, else the first declared folder, else a media app's first present
drive's media folder. The data tab lists each drive's media folders; a folder whose drive is not bound
into FileBrowser is text, never a link.

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-16 15:19:14 +02:00

130 lines
4.7 KiB
HTML

{{define "app_guide"}}
{{template "layout_start" .}}
<div class="app-page">
{{template "app_shell_start" .}}
{{/* „UTMUTATO" — the app's own copy, and the WHOLE page for an app that is not installed yet.
It replaces the old details page: description and screenshots, what it is for, the first steps,
the guide the catalog carries, the questions people ask, and the official documentation.
THE GUIDE RENDERS ONLY WHEN ITS AUTHOR NAMED THE VERSION THEY CHECKED IT AGAINST
(AppGuide.Rendered). A guide walking the household through a screen two releases old is worse
than no guide, so an unchecked one is not shown and the page says a guide is still to come.
Everything here is PLAIN TEXT through html/template. No markdown, no raw HTML: a step that
contains a tag is shown as the characters the author typed. */}}
<script>
// Defined BEFORE the images: an error event can fire as soon as an <img> is parsed.
function appShotGone(img) {
img.style.display = 'none';
var box = img.parentNode, left = false;
box.querySelectorAll('img').forEach(function (i) { if (i.style.display !== 'none') { left = true; } });
if (!left) { box.closest('.app-section').style.display = 'none'; }
}
</script>
<!-- Screenshots (graceful — each hidden if its asset does not exist, and the section with the last
one, so a panel is never drawn around nothing) -->
<div class="app-section" data-screenshots-section="1">
<div class="app-screenshots" id="screenshots">
<img src="{{screenshotURL .Meta.Slug 1}}" alt="" class="app-screenshot"
onerror="appShotGone(this)">
<img src="{{screenshotURL .Meta.Slug 2}}" alt="" class="app-screenshot"
onerror="appShotGone(this)">
<img src="{{screenshotURL .Meta.Slug 3}}" alt="" class="app-screenshot"
onerror="appShotGone(this)">
</div>
</div>
{{if not .Deployed}}
{{/* The install button lives on this tab, because this tab IS the page for a not-installed app.
The server refuses a non-installable template regardless; hiding the button keeps the page
from offering an action that would be rejected. */}}
<div class="app-section">
{{if canInstall .Meta}}
<a href="/apps/{{.Meta.Slug}}/install" class="btn btn-primary" data-install-cta="1"
onclick="return checkBeforeDeploy(event, '{{.Stack.Name}}')">{{T "app_info.telepites"}}</a>
{{else}}
<p class="form-hint" data-not-installable="1">{{T "app_page.not_installable"}}</p>
{{end}}
</div>
{{end}}
<div class="app-sections">
{{if .AppInfo.UseCases}}
<div class="app-section">
<h3>{{T "app_info.mire_hasznalhato"}}</h3>
<ul class="app-info-list">
{{range .AppInfo.UseCases}}<li>{{.}}</li>{{end}}
</ul>
</div>
{{end}}
{{if .AppInfo.FirstSteps}}
<div class="app-section">
<h3>{{T "app_info.elso_lepesek"}}</h3>
<ol class="app-info-list">
{{range .AppInfo.FirstSteps}}<li>{{.}}</li>{{end}}
</ol>
</div>
{{end}}
{{if .AppInfo.Prerequisites}}
<div class="app-section">
<h3>{{T "app_info.elofeltetelek"}}</h3>
<ul class="app-info-list">
{{range .AppInfo.Prerequisites}}<li>{{.}}</li>{{end}}
</ul>
</div>
{{end}}
</div>
{{/* THE GUIDE. */}}
{{if .AppInfo.Guide.Rendered}}
<div class="app-guide" data-guide="1" data-guide-checked="{{.AppInfo.Guide.CheckedVersion}}">
{{- range .AppInfo.Guide.Sections}}
<div class="app-section" data-guide-section="1">
<h3>{{.Title}}</h3>
{{if .Intro}}<p>{{.Intro}}</p>{{end}}
{{if .Steps}}
<ol class="app-info-list">
{{- range .Steps}}<li>{{.}}</li>{{end}}
</ol>
{{end}}
</div>
{{- end}}
{{- if .AppInfo.Guide.FAQ}}
<div class="app-section" data-guide-faq="1">
<h3>{{T "app_page.faq"}}</h3>
<dl class="app-faq">
{{- range .AppInfo.Guide.FAQ}}
<dt>{{.Q}}</dt>
<dd>{{.A}}</dd>
{{- end}}
</dl>
</div>
{{- end}}
</div>
{{else if .InfraInfo}}
{{/* v0.320.0: part of the box — what it is, in two lines, instead of „a guide is still to come". */}}
<div class="app-section" data-infra-guide="1">
<p>{{.InfraInfo.Description}}</p>
<p>{{T "app_page.infra_guide"}}</p>
</div>
{{else}}
<div class="app-section" data-guide-missing="1"><p>{{T "app_page.guide_missing"}}</p></div>
{{end}}
<div class="app-sections">
{{if .AppInfo.DocsURL}}
<div class="app-section">
<h3>{{T "app_info.dokumentacio"}}</h3>
<p><a href="{{.AppInfo.DocsURL}}" target="_blank" class="app-info-link">{{T "app_info.hivatalos_dokumentacio"}}</a></p>
</div>
{{end}}</div>
{{template "app_press_script" .}}
</div>{{/* .app-page */}}
{{template "layout_end" .}}
{{end}}