{{define "status"}} {{if .Flash}}
{{.Flash}}
{{end}} {{/* Approvals come FIRST and before anything else on the page. They are the only thing here that is waiting on the person, and everything below is still true in a minute. */}} {{/* Asks waiting on THIS machine as your approval device (uidevice.go). They are answered in the approvals popup, which the tray and the notification open; the front page says they are there and links to it. */}} {{if .DeviceApprovals}}
{{len .DeviceApprovals}} request{{if gt (len .DeviceApprovals) 1}}s{{end}} from your hosts {{if gt (len .DeviceApprovals) 1}}are{{else}}is{{end}} waiting for your approval

Open approvals to read and answer {{if gt (len .DeviceApprovals) 1}}them{{else}}it{{end}}.

{{end}} {{if .Approvals}}

Waiting for you

{{template "stepup-approvals" .}} {{end}} {{/* WHAT HAS HAPPENED HERE — above the state block on purpose. The template's own rule for the approvals is that everything below them "is still true in a minute"; the state block is exactly that, and a host having killed the programs you were running is not. It is news, it is the only thing on this page the user neither did nor was asked about, and nobody would think to scroll for it. */}} {{if .Refusal}}

This machine refused something your host asked for

{{.Refusal.At}}

Refused: {{.Refusal.What}}

{{.Refusal.Why}}

Your host is told this on its next check-in, so it is not left waiting on something that is never going to happen.

{{end}} {{if .Events}}

What your host has done on this machine

{{range .Events}}
{{.At}}

{{.Text}}

{{end}} {{end}}

{{.State}}

{{if .StateNote}}

{{.StateNote}}

{{end}}

Hosts this machine serves

{{if not .Pairings}}
No host is paired yet.

Pair one with a token from your host's “Set up a bastion”.

{{end}} {{range .Pairings}}
{{.Host}} {{if .IsAnchor}}anchor{{end}} {{if eq .State "pending"}}waiting for approval{{end}} {{if eq .State "revoked"}}revoked{{end}} {{if eq .State "invalid"}}invalid, not served{{end}}
Local port
{{.ListenAddr}} {{if .Listening}}answering {{else}}not answering{{end}}
{{if .TunnelIP}}
Tunnel address
{{.TunnelIP}}
{{end}} {{if .FirstSeen}}
Paired since
{{.FirstSeen}}
{{end}}
{{end}}

This machine

Mode
{{.Mode}}{{if .ModeNote}} — {{.ModeNote}}{{end}}
Anchor
{{if .AnchorHost}}
{{.AnchorHost}}{{if .AnchorOwner}} (owner “{{.AnchorOwner}}”){{end}}
{{else}}
none{{if .AnchorRequired}} required{{end}}
{{end}}
Owner
{{if .Owner}}{{.Owner}}{{else}}not claimed{{end}}
Version
{{.Version}}{{if .UpdateAvailable}} {{.UpdateAvailable}} available{{end}}
{{if .AnchorRequired}}
This machine is networked but not anchored, so it answers nothing: no host may run an op, open a terminal or place anything here until one of them is made the anchor. Run sudo -H privatae-bastion claim-anchor on this machine.
{{end}} {{if .UpdateAvailable}} {{/* Says where the control IS, because it is not here and must not be. The bastion does not update itself — a host directs it (update.go) — and a local UI that grew an Update button would be the first step across the line in ui.go's header. Naming a version without naming who installs it sends someone looking for a button this page will never have. */}}
Version {{.UpdateAvailable}} has been published. This machine will not install it on its own: your host directs updates. Open the Network app on your host, find this machine under Bastions, and use Update there. Nothing changes here until it does.
{{end}} {{if .NoConsoleNote}}
After it updates itself the bastion restarts with no console window, which is why nothing appears on screen while it runs. Task Manager → privatae-bastion.exe is where it lives.
{{end}}

Checked {{.CheckedAt}}.

{{end}} {{define "stepup-approvals"}} {{range .Approvals}}
{{.Host}} is asking {{.Short}}
{{if .Unreadable}}

This machine cannot tell you what is being asked for.

It does not recognise this kind of request, which usually means your host is newer than the bastion here. Deny it and update this machine — approving something neither of you can read is not worth the risk.

{{else}} {{range .Lines}}

{{.}}

{{end}} {{end}} {{/* When the request cannot be described, Deny leads and Approve is demoted: the green button must never be the easy one next to text that says nothing. */}}
{{if $.ApprovalsView}}{{end}}
{{if $.ApprovalsView}}{{end}} {{/* What these words describe, so the tray's lane approves exactly the request that was read (approvalpipe.go). */}}

The code comes from the authenticator you enrolled on this machine. Your host never sees it.

{{end}} {{end}}