216 lines
8.1 KiB
HTML
216 lines
8.1 KiB
HTML
{{define "portal.html"}}
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{.Title}} · TAPM</title>
|
|
<link rel="stylesheet" href="/static/app.css">
|
|
<script src="/static/app.js" defer></script>
|
|
</head>
|
|
<body>
|
|
{{template "topbar" .}}
|
|
|
|
<main class="page">
|
|
{{if .NewCode}}
|
|
<section class="code-reveal" aria-live="polite">
|
|
<div>
|
|
<p class="eyebrow">Deployment authorization created</p>
|
|
<h2 id="new-code">{{.NewCode}}</h2>
|
|
<p>Share this code only with the technician performing the deployment.</p>
|
|
</div>
|
|
<button class="button light" type="button" data-copy="#new-code">Copy code</button>
|
|
</section>
|
|
{{end}}
|
|
|
|
{{if .Notice}}<div class="notice">{{.Notice}}</div>{{end}}
|
|
|
|
<section class="hero">
|
|
<div>
|
|
<p class="eyebrow">Controlled package delivery</p>
|
|
<h1>Open a deployment window.</h1>
|
|
<p>
|
|
Authorize a limited number of hosts for selected packages and
|
|
installer actions. Access closes automatically at the end of the window.
|
|
</p>
|
|
</div>
|
|
<div class="policy-card">
|
|
<span>Default policy</span>
|
|
<strong>{{.DefaultHostLimit}} hosts</strong>
|
|
<strong>{{.DefaultDays}} days</strong>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="content-grid">
|
|
<section class="panel create-panel">
|
|
<div class="panel-heading">
|
|
<div>
|
|
<p class="eyebrow">New authorization</p>
|
|
<h2>Create deployment code</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<form action="/portal/authorizations" method="post" class="stack">
|
|
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
|
<label>
|
|
Customer or deployment label
|
|
<input name="customer_label" maxlength="255" placeholder="Example: Acme cluster refresh">
|
|
</label>
|
|
|
|
<div class="field-row">
|
|
<label>
|
|
Maximum hosts
|
|
<input name="host_limit" type="number" min="1" max="{{.MaxHostLimit}}" value="{{.DefaultHostLimit}}" required>
|
|
</label>
|
|
<label>
|
|
Duration in days
|
|
<input name="duration_days" type="number" min="1" max="90" value="{{.DefaultDays}}" required>
|
|
</label>
|
|
</div>
|
|
|
|
<fieldset>
|
|
<legend>Allowed packages</legend>
|
|
{{range .Packages}}
|
|
{{if .Enabled}}
|
|
<label class="package-choice">
|
|
<input type="checkbox" name="package_id" value="{{.ID}}">
|
|
<span>
|
|
<strong>{{.DisplayName}}</strong>
|
|
<small>{{.PackageVersion}}</small>
|
|
</span>
|
|
</label>
|
|
{{end}}
|
|
{{else}}
|
|
<p class="empty">No packages have been enabled yet.</p>
|
|
{{end}}
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
<legend>Allowed installer actions</legend>
|
|
{{range .Actions}}
|
|
{{if .Enabled}}
|
|
<label class="package-choice">
|
|
<input type="checkbox" name="action_slug" value="{{.Slug}}">
|
|
<span>
|
|
<strong>{{.DisplayName}}</strong>
|
|
<small>Authorization gate</small>
|
|
</span>
|
|
</label>
|
|
{{end}}
|
|
{{else}}
|
|
<p class="empty">No installer actions have been enabled.</p>
|
|
{{end}}
|
|
</fieldset>
|
|
|
|
<button class="button primary" type="submit">Create deployment code</button>
|
|
</form>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<div class="panel-heading">
|
|
<div>
|
|
<p class="eyebrow">Recent activity</p>
|
|
<h2>Deployment authorizations</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="authorization-list">
|
|
{{range .Authorizations}}
|
|
{{$authorization := .}}
|
|
<article class="authorization {{if isActive .}}active{{else}}closed{{end}}">
|
|
<div class="authorization-top">
|
|
<div>
|
|
<strong>{{if .CustomerLabel}}{{.CustomerLabel}}{{else}}Unlabeled deployment{{end}}</strong>
|
|
<span class="status">{{if isActive .}}Active{{else}}Closed{{end}}</span>
|
|
</div>
|
|
<span class="code-hint">•••••{{.CodeHint}}</span>
|
|
</div>
|
|
<dl>
|
|
<div><dt>Hosts</dt><dd>{{.HostCount}} / {{.HostLimit}}</dd></div>
|
|
<div><dt>Expires</dt><dd>{{formatTime .ExpiresAt}}</dd></div>
|
|
<div><dt>Packages</dt><dd>{{if .Packages}}{{.Packages}}{{else}}None{{end}}</dd></div>
|
|
<div><dt>Actions</dt><dd>{{if .Actions}}{{.Actions}}{{else}}None{{end}}</dd></div>
|
|
<div><dt>Created by</dt><dd>{{.CreatedBy}}</dd></div>
|
|
</dl>
|
|
{{if isActive .}}
|
|
<details class="authorization-editor">
|
|
<summary>Edit access</summary>
|
|
<form action="/portal/authorizations/{{.ID}}/update" method="post" class="stack compact">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
<div class="field-row">
|
|
<label>
|
|
Maximum hosts
|
|
<input name="host_limit" type="number" min="1" max="{{$.MaxHostLimit}}" value="{{.HostLimit}}" required>
|
|
</label>
|
|
<label>
|
|
Extend by days
|
|
<input name="extend_days" type="number" min="0" max="90" value="0" required>
|
|
</label>
|
|
</div>
|
|
<small class="form-help">Use 0 to keep the current expiration. Extensions are added to the existing deadline.</small>
|
|
|
|
<fieldset>
|
|
<legend>Allowed packages</legend>
|
|
{{range $.Packages}}
|
|
{{if .Enabled}}
|
|
<label class="package-choice">
|
|
<input type="checkbox" name="package_id" value="{{.ID}}" {{if index $authorization.PackageIDs .ID}}checked{{end}}>
|
|
<span>
|
|
<strong>{{.DisplayName}}</strong>
|
|
<small>{{.PackageVersion}}</small>
|
|
</span>
|
|
</label>
|
|
{{end}}
|
|
{{else}}
|
|
<p class="empty">No packages have been enabled yet.</p>
|
|
{{end}}
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
<legend>Allowed installer actions</legend>
|
|
{{range $.Actions}}
|
|
{{if .Enabled}}
|
|
<label class="package-choice">
|
|
<input type="checkbox" name="action_slug" value="{{.Slug}}" {{if index $authorization.ActionSlugs .Slug}}checked{{end}}>
|
|
<span>
|
|
<strong>{{.DisplayName}}</strong>
|
|
<small>Authorization gate</small>
|
|
</span>
|
|
</label>
|
|
{{end}}
|
|
{{else}}
|
|
<p class="empty">No installer actions have been enabled.</p>
|
|
{{end}}
|
|
</fieldset>
|
|
|
|
<button class="button secondary" type="submit">Save authorization</button>
|
|
</form>
|
|
</details>
|
|
<form class="authorization-revoke" action="/portal/authorizations/{{.ID}}/revoke" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
<button class="text-button danger" type="submit">Revoke now</button>
|
|
</form>
|
|
{{end}}
|
|
</article>
|
|
{{else}}
|
|
<p class="empty authorization-empty">No deployment authorizations have been created.</p>
|
|
{{end}}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<section class="panel audit-panel">
|
|
<div class="panel-heading panel-heading-action">
|
|
<div>
|
|
<p class="eyebrow">Audit preview</p>
|
|
<h2>Latest 15 security events</h2>
|
|
</div>
|
|
<a class="button secondary" href="/portal/audit">Review full audit trail</a>
|
|
</div>
|
|
{{template "audit-rows" .}}
|
|
</section>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
{{end}}
|