update_server/web/templates/pages/project_detail.gohtml
2026-06-10 20:51:17 +03:00

200 lines
7.6 KiB
Text

{{define "content"}}
<section class="hero hero-split">
<div>
<p class="eyebrow">{{.Eyebrow}}</p>
<h1>{{.Heading}}</h1>
<p class="lede">{{.Description}}</p>
</div>
<div class="hero-meta">
<span class="pill {{if .Project.IsActive}}pill-success{{else}}pill-muted{{end}}">
{{if .Project.IsActive}}Active{{else}}Archived{{end}}
</span>
<p class="resource-slug">{{.Project.Slug}}</p>
</div>
</section>
{{if .Form.Error}}
<section class="alert-card alert-error">
<p>{{.Form.Error}}</p>
</section>
{{end}}
<section class="section-grid">
<article class="section-card">
<div class="section-heading">
<h2>Project Details</h2>
<p>Edit the stable metadata used by the admin UI and future client endpoints.</p>
</div>
<form class="stack-form" method="post" action="{{.Form.Action}}">
{{template "csrf_field" .}}
<label class="field">
<span>Name</span>
<input type="text" name="name" value="{{.Form.Name}}" maxlength="120" required>
</label>
<label class="field">
<span>Slug</span>
<input type="text" name="slug" value="{{.Form.Slug}}" maxlength="120" required>
</label>
<label class="field">
<span>Description</span>
<textarea name="description" rows="4">{{.Form.Description}}</textarea>
</label>
<button class="button" type="submit">{{.Form.SubmitLabel}}</button>
</form>
</article>
<article class="section-card">
<div class="section-heading">
<h2>Lifecycle</h2>
<p>Archive projects to hide them operationally without deleting their data.</p>
</div>
<p class="meta-line"><strong>Created:</strong> {{.Project.CreatedAt.Format "2006-01-02 15:04 UTC"}}</p>
<p class="meta-line"><strong>Updated:</strong> {{.Project.UpdatedAt.Format "2006-01-02 15:04 UTC"}}</p>
<form class="stack-form" method="post" action="{{.ArchiveAction}}">
{{template "csrf_field" .}}
<input type="hidden" name="state" value="{{.ArchiveState}}">
<button class="button button-secondary" type="submit">{{.ArchiveLabel}}</button>
</form>
</article>
</section>
<section class="section-grid">
<article class="section-card">
<div class="section-heading">
<h2>Project Tags</h2>
<p>Tags are available from day one so projects can be grouped immediately.</p>
</div>
{{if .Tags}}
<div class="chip-list">
{{range .Tags}}
<form class="chip-form" method="post" action="/admin/projects/{{$.Project.ID}}/tags/{{.ID}}/detach">
{{template "csrf_field" $}}
<span class="chip-label">{{.Name}}</span>
<button class="chip-remove" type="submit">Detach</button>
</form>
{{end}}
</div>
{{else}}
<p class="empty-copy">No tags attached yet.</p>
{{end}}
{{if .AvailableTags}}
<form class="inline-form" method="post" action="{{.AttachTagAction}}">
{{template "csrf_field" .}}
<label class="field">
<span>Attach tag</span>
<select name="tag_id" required>
<option value="">Choose a tag</option>
{{range .AvailableTags}}
<option value="{{.ID}}">{{.Name}} ({{.Slug}})</option>
{{end}}
</select>
</label>
<button class="button" type="submit">Attach tag</button>
</form>
{{else}}
<p class="empty-copy">All existing tags are already attached. <a href="/admin/tags/new">Create another tag</a> if you need a new grouping.</p>
{{end}}
</article>
<article class="section-card">
<div class="section-heading">
<h2>Release Upload</h2>
<p>Uploads are stored outside the public web root and each release records its checksum, size, and storage path.</p>
</div>
{{if .Upload.Error}}
<section class="alert-card alert-error compact-alert">
<p>{{.Upload.Error}}</p>
</section>
{{end}}
<form class="stack-form" method="post" action="{{.Upload.Action}}" enctype="multipart/form-data">
{{template "csrf_field" .}}
<label class="field">
<span>Version</span>
<input type="text" name="version" value="{{.Upload.Version}}" maxlength="120" placeholder="1.0.0" required>
</label>
<label class="field">
<span>Build</span>
<input type="text" name="build" value="{{.Upload.Build}}" maxlength="120" placeholder="optional build label">
</label>
<label class="field">
<span>Release notes</span>
<textarea name="release_notes" rows="4">{{.Upload.ReleaseNotes}}</textarea>
</label>
<label class="field">
<span>Artifact file</span>
<input type="file" name="artifact" required>
</label>
<p class="helper-copy">Maximum upload size: {{.Upload.MaxUploadMB}} MB.</p>
<button class="button" type="submit">Upload release</button>
</form>
</article>
</section>
<section class="section-card section-card-wide">
<div class="section-heading">
<h2>Release History</h2>
<p>Each release row keeps the sanitized filename, checksum, file size, content type, and private storage path for later download endpoints.</p>
</div>
{{if .Releases}}
<div class="release-list">
{{range .Releases}}
<article class="release-card">
<div class="release-head">
<h3>{{.Release.Version}}{{if .Release.Build}} <span class="release-build">{{.Release.Build}}</span>{{end}}</h3>
<span class="pill pill-soft">{{.Release.ContentType}}</span>
</div>
<p class="meta-line"><strong>File:</strong> {{.Release.Filename}}</p>
<p class="meta-line"><strong>Checksum:</strong> <code>{{.Release.ChecksumSHA256}}</code></p>
<p class="meta-line"><strong>Storage path:</strong> <code>{{.Release.StoragePath}}</code></p>
<p class="meta-line"><strong>Size:</strong> {{.Release.SizeBytes}} bytes</p>
<p class="meta-line"><strong>Uploaded by:</strong> {{if .UploadedByEmail}}{{.UploadedByEmail}}{{else}}Unknown{{end}}</p>
<p class="meta-line"><strong>Created:</strong> {{.Release.CreatedAt.Format "2006-01-02 15:04 UTC"}}</p>
{{if .Release.ReleaseNotes}}
<p class="release-notes">{{.Release.ReleaseNotes}}</p>
{{end}}
</article>
{{end}}
</div>
{{else}}
<p class="empty-copy">No releases uploaded for this project yet.</p>
{{end}}
</section>
<section class="section-card section-card-wide">
<div class="section-heading">
<h2>Client API</h2>
<p>Use these bearer-authenticated endpoints from client applications after you create an API key with download access.</p>
</div>
{{if .Project.IsActive}}
<div class="endpoint-list">
<p class="meta-line"><strong>Project listing:</strong> <code>{{.BaseURL}}/api/v1/projects</code></p>
<p class="meta-line"><strong>Latest release metadata:</strong> <code>{{printf "%s/api/v1/projects/%s/releases/latest" .BaseURL .Project.Slug}}</code></p>
{{if .LatestRelease}}
<p class="meta-line"><strong>Release metadata:</strong> <code>{{printf "%s/api/v1/releases/%d" .BaseURL .LatestRelease.ID}}</code></p>
<p class="meta-line"><strong>Artifact download:</strong> <code>{{printf "%s/api/v1/releases/%d/download" .BaseURL .LatestRelease.ID}}</code></p>
<p class="meta-line"><strong>Current latest:</strong> Version {{.LatestRelease.Version}}{{if .LatestRelease.Build}} (build {{.LatestRelease.Build}}){{end}}, release ID {{.LatestRelease.ID}}.</p>
{{else}}
<p class="empty-copy">Upload the first release to activate the metadata and download endpoints for this project.</p>
{{end}}
</div>
{{else}}
<p class="empty-copy">This project is archived, so client API lookups and downloads will hide it until you restore the project.</p>
{{end}}
</section>
{{end}}