Refactor web build process and update documentation

- Removed Node.js build artifacts from .gitignore and adjusted Makefile to reflect changes in web UI build process, now using server-rendered Go templates instead of React.
- Updated README to clarify the new web UI architecture and output formats, emphasizing the removal of the Node.js build step.
- Added a command to set the number of frames per render task in manager configuration, enhancing user control over rendering settings.
- Improved Gitea workflow by removing unnecessary npm install step, streamlining the CI process.
This commit is contained in:
2026-03-12 19:44:40 -05:00
parent d3c5ee0dba
commit 2deb47e5ad
78 changed files with 3895 additions and 12499 deletions

View File

@@ -0,0 +1,36 @@
{{ define "partial_admin_apikeys" }}
{{ $keys := index . "keys" }}
{{ if not $keys }}
<p>No API keys generated yet.</p>
{{ else }}
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Scope</th>
<th>Prefix</th>
<th>Active</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{ range $key := $keys }}
<tr>
<td>{{ $key.ID }}</td>
<td>{{ $key.Name }}</td>
<td>{{ $key.Scope }}</td>
<td>{{ $key.Key }}</td>
<td>{{ if $key.IsActive }}yes{{ else }}no{{ end }}</td>
<td>{{ formatTime $key.CreatedAt }}</td>
<td class="row">
<button class="btn tiny" data-revoke-apikey="{{ $key.ID }}">Revoke</button>
<button class="btn tiny danger" data-delete-apikey="{{ $key.ID }}">Delete</button>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,35 @@
{{ define "partial_admin_runners" }}
{{ $runners := index . "runners" }}
{{ if not $runners }}
<p>No runners registered.</p>
{{ else }}
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Host</th>
<th>Status</th>
<th>Priority</th>
<th>Heartbeat</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{ range $runner := $runners }}
<tr>
<td>{{ $runner.ID }}</td>
<td>{{ $runner.Name }}</td>
<td>{{ $runner.Hostname }}</td>
<td><span class="status {{ statusClass $runner.Status }}">{{ $runner.Status }}</span></td>
<td>{{ $runner.Priority }}</td>
<td>{{ formatTime $runner.LastHeartbeat }}</td>
<td class="row">
<button class="btn tiny danger" data-delete-runner="{{ $runner.ID }}">Delete</button>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,44 @@
{{ define "partial_admin_users" }}
{{ $users := index . "users" }}
{{ $currentUserID := index . "current_user_id" }}
{{ if not $users }}
<p>No users found.</p>
{{ else }}
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Provider</th>
<th>Admin</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{ range $user := $users }}
<tr>
<td>{{ $user.ID }}</td>
<td>{{ $user.Name }}</td>
<td>{{ $user.Email }}</td>
<td>{{ if $user.OAuthProvider }}{{ $user.OAuthProvider }}{{ else }}local{{ end }}</td>
<td>{{ if $user.IsAdmin }}yes{{ else }}no{{ end }}</td>
<td>{{ formatTime $user.CreatedAt }}</td>
<td class="row">
{{ if and $user.IsAdmin (eq $user.ID $currentUserID) }}
<button class="btn tiny" disabled title="You cannot revoke your own admin status">
Revoke Admin
</button>
{{ else }}
<button class="btn tiny" data-set-admin="{{ $user.ID }}" data-admin-value="{{ if $user.IsAdmin }}false{{ else }}true{{ end }}">
{{ if $user.IsAdmin }}Revoke Admin{{ else }}Make Admin{{ end }}
</button>
{{ end }}
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,82 @@
{{ define "partial_job_files" }}
{{ $jobID := index . "job_id" }}
{{ $files := index . "files" }}
{{ $isAdmin := index . "is_admin" }}
{{ $adminInputFiles := index . "admin_input_files" }}
{{ if not $files }}
<p>No output files found yet.</p>
{{ else }}
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
{{ if $isAdmin }}<th>Type</th>{{ end }}
<th>Size</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{ range $file := $files }}
<tr>
<td>{{ $file.ID }}</td>
<td>{{ $file.FileName }}</td>
{{ if $isAdmin }}<td>{{ $file.FileType }}</td>{{ end }}
<td>{{ $file.FileSize }}</td>
<td>{{ formatTime $file.CreatedAt }}</td>
<td class="row">
<a class="btn tiny" href="/api/jobs/{{ $jobID }}/files/{{ $file.ID }}/download">Download</a>
{{ if hasSuffixFold $file.FileName ".exr" }}
<button
type="button"
class="btn tiny"
data-exr-preview-url="/api/jobs/{{ $jobID }}/files/{{ $file.ID }}/preview-exr"
data-exr-preview-name="{{ $file.FileName }}"
>
Preview
</button>
{{ end }}
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
{{ if $isAdmin }}
<details class="admin-context">
<summary>Admin: context/input files</summary>
{{ if not $adminInputFiles }}
<p>No context/input files found.</p>
{{ else }}
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Type</th>
<th>Size</th>
<th>Created</th>
<th>Download</th>
</tr>
</thead>
<tbody>
{{ range $file := $adminInputFiles }}
<tr>
<td>{{ $file.ID }}</td>
<td>{{ $file.FileName }}</td>
<td>{{ $file.FileType }}</td>
<td>{{ $file.FileSize }}</td>
<td>{{ formatTime $file.CreatedAt }}</td>
<td>
<a class="btn tiny" href="/api/jobs/{{ $jobID }}/files/{{ $file.ID }}/download">Download</a>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
</details>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,37 @@
{{ define "partial_job_tasks" }}
{{ $tasks := index . "tasks" }}
{{ if not $tasks }}
<p>No tasks yet.</p>
{{ else }}
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Type</th>
<th>Status</th>
<th>Frame(s)</th>
<th>Step</th>
<th>Retries</th>
<th>Error</th>
<th>Logs</th>
</tr>
</thead>
<tbody>
{{ range $task := $tasks }}
<tr>
<td>{{ $task.ID }}</td>
<td>{{ $task.TaskType }}</td>
<td><span class="status {{ statusClass $task.Status }}">{{ $task.Status }}</span></td>
<td>{{ $task.Frame }}{{ if $task.FrameEnd }}-{{ derefInt $task.FrameEnd }}{{ end }}</td>
<td>{{ if $task.CurrentStep }}{{ $task.CurrentStep }}{{ else }}-{{ end }}</td>
<td>{{ $task.RetryCount }}</td>
<td>{{ if $task.Error }}{{ $task.Error }}{{ else }}-{{ end }}</td>
<td>
<button class="btn tiny" data-view-logs-task-id="{{ $task.ID }}">View logs</button>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,40 @@
{{ define "partial_jobs_table" }}
{{ $jobs := index . "jobs" }}
{{ if not $jobs }}
<p>No jobs yet. Submit one to get started.</p>
{{ else }}
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Progress</th>
<th>Frames</th>
<th>Format</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{ range $job := $jobs }}
<tr>
<td><a class="job-link" href="/jobs/{{ $job.ID }}">{{ $job.Name }}</a></td>
<td><span class="status {{ statusClass $job.Status }}">{{ $job.Status }}</span></td>
<td>{{ progressInt $job.Progress }}%</td>
<td>{{ if $job.FrameStart }}{{ derefInt $job.FrameStart }}{{ end }}{{ if $job.FrameEnd }}-{{ derefInt $job.FrameEnd }}{{ end }}</td>
<td>{{ if $job.OutputFormat }}{{ derefString $job.OutputFormat }}{{ else }}-{{ end }}</td>
<td>{{ formatTime $job.CreatedAt }}</td>
<td class="row">
{{ if or (eq $job.Status "pending") (eq $job.Status "running") }}
<button class="btn tiny" data-cancel-job="{{ $job.ID }}">Cancel</button>
{{ end }}
{{ if or (eq $job.Status "completed") (eq $job.Status "failed") (eq $job.Status "cancelled") }}
<button class="btn tiny danger" data-delete-job="{{ $job.ID }}">Delete</button>
{{ end }}
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
{{ end }}