105 lines
5.7 KiB
HTML
105 lines
5.7 KiB
HTML
{{define "content"}}
|
|
<div class="hdr">
|
|
<h1>Services</h1>
|
|
</div>
|
|
<div class="tools">
|
|
<label class="search">
|
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="6.5" cy="6.5" r="5"></circle><path d="M10.3 10.3L14 14"></path></svg>
|
|
<input type="search" id="q" placeholder="Search services" aria-label="Search services" autocomplete="off">
|
|
</label>
|
|
<div class="end">
|
|
<span class="lbl" id="showlbl">Show</span>
|
|
<div class="seg" role="group" aria-labelledby="showlbl">
|
|
<button type="button" data-display="icon" aria-pressed="false">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><rect x="2" y="2" width="10" height="10" rx="2.5"></rect></svg>
|
|
Icon
|
|
</button>
|
|
<button type="button" data-display="both" aria-pressed="true">
|
|
<svg width="18" height="14" viewBox="0 0 18 14" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><rect x="1" y="3" width="8" height="8" rx="2"></rect><path d="M12 7h5"></path></svg>
|
|
Icon + text
|
|
</button>
|
|
<button type="button" data-display="text" aria-pressed="false">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M2 4.5h10M2 9.5h7"></path></svg>
|
|
Text
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="services" hx-get="/fragments/services" hx-trigger="sse:services, sse:agents" hx-swap="innerHTML">
|
|
{{template "services" .}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{/* The machine filter in the sidebar. The page defines it; the services fragment replaces its links out of band. */}}
|
|
{{define "machines"}}
|
|
<div class="mblock">
|
|
<div class="slabel">Machines</div>
|
|
<nav class="mlist" id="machines" aria-label="Filter by machine">{{template "machine-links" .}}</nav>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "machine-links"}}
|
|
<a class="cur" href="/" aria-current="true" data-machine="">All <span class="n">{{.ServiceCount}}</span></a>
|
|
{{range .Groups}}
|
|
<a href="/"{{if .Sub}} class="sub"{{end}} data-machine="{{.Key}}">{{if .Cluster}}<span class="sw-icon" aria-hidden="true"></span>{{else}}<span class="mdot{{if .Offline}} off{{end}}" aria-hidden="true"></span>{{end}}{{.Title}} <span class="n">{{len .Services}}</span></a>
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{/* What /fragments/services returns: the groups, and the machine filter swapped in out of band. */}}
|
|
{{define "services-fragment"}}
|
|
{{template "services" .}}
|
|
<div id="machines" hx-swap-oob="innerHTML">{{template "machine-links" .}}</div>
|
|
{{end}}
|
|
|
|
{{define "services"}}
|
|
{{if .Sprite}}<svg class="sprite" aria-hidden="true">{{range .Sprite}}<symbol id="si-{{.Slug}}" viewBox="0 0 24 24"><path fill="currentColor" d="{{.Path}}"/></symbol>{{end}}</svg>{{end}}
|
|
{{range .Groups}}
|
|
<section class="grp{{if .Offline}} offline{{end}}" data-key="{{.Key}}" aria-label="{{.Title}}">
|
|
<div class="gh">
|
|
<h2{{if .TitleHint}} title="{{.TitleHint}}"{{end}}>{{.Title}}</h2>
|
|
<span class="kind">{{.Kind}}</span>
|
|
{{if .Meta}}<span class="meta">{{.Meta}}</span>{{end}}
|
|
{{if .Offline}}<span class="warn">{{.OfflineLabel}}{{with .OfflineSince}} since <time datetime="{{.Format "2006-01-02T15:04:05Z07:00"}}">{{.Format "15:04"}}</time>{{end}} · showing last known state</span>{{end}}
|
|
<span class="count">{{len .Services}}</span>
|
|
</div>
|
|
{{range .Services}}
|
|
<div class="row" data-search="{{.Search}}">
|
|
<div class="nm">
|
|
<a href="/services/{{.ID}}" title="{{.DisplayName}}" aria-label="{{.DisplayName}}">
|
|
{{if .Icon}}<span class="ico" aria-hidden="true"><svg width="15" height="15" viewBox="0 0 24 24"><use href="#si-{{.Icon}}"></use></svg></span>{{else}}<span class="ltr {{.LetterClass}}" aria-hidden="true">{{.Letter}}</span>{{end}}
|
|
<span class="nmt">{{.Name}}</span>
|
|
</a>
|
|
{{if .Stack}}<span class="stk">{{.Stack}}</span>{{end}}
|
|
</div>
|
|
<div class="ver" title="{{.ActualRef}}"><span class="r">{{.Repo}}</span><span class="t"><b>{{.Tag}}</b>{{.Digest}}</span></div>
|
|
<div class="stc">
|
|
<span class="st {{.StatusClass}}"><svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><circle cx="5" cy="5" r="4" stroke="currentColor" stroke-width="1.5"></circle></svg>{{.StatusLabel}}</span>
|
|
</div>
|
|
<div class="flags">
|
|
{{if .AvailableRef}}<span class="tag f-up" title="{{.AvailableRef}}">Update available<em>{{.AvailableTag}}</em></span>{{end}}
|
|
{{if .NewerTag}}<span class="tag f-newer" title="{{.NewerRef}}">Newer tag<em>{{.NewerTag}}</em></span>{{end}}
|
|
{{if followsNoTag .Service}}<span class="tag f-notag">Follows no tag</span>{{end}}
|
|
{{if .LastPollError}}<span class="tag f-err" title="{{.LastPollError}}">Poll failed</span>{{end}}
|
|
{{if .Self}}<span class="tag f-out">Managed outside</span>{{end}}
|
|
</div>
|
|
<div class="mode">
|
|
{{if .Self}}<span class="na">n/a</span>
|
|
{{else}}<form method="post" action="/services/{{.ID}}/mode">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRF}}">
|
|
<input type="hidden" name="return" value="overview">
|
|
{{if eq .UpdateMode "auto"}}<input type="hidden" name="mode" value="manual">
|
|
<button type="submit" class="sw" role="switch" aria-checked="true"><i></i>Auto</button>
|
|
{{else}}<input type="hidden" name="mode" value="auto">
|
|
<button type="submit" class="sw" role="switch" aria-checked="false"{{if .AutoBlocked}} disabled title="{{.AutoBlocked}}"{{end}}><i></i>Manual</button>
|
|
{{if .AutoBlocked}}<span class="na">{{.AutoBlocked}}</span>{{end}}{{end}}
|
|
</form>{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</section>
|
|
{{else}}
|
|
<p>No services reported yet. <a href="/agents?add=1">Add an agent</a> to get started.</p>
|
|
{{end}}
|
|
<p class="nomatch" id="nomatch" hidden>No services match.</p>
|
|
{{end}}
|