This PR breaks the large web and player bootstrap files into smaller modules with clearer ownership.

Web changes:

Split shared helpers, bootstrap logic, route groups, and upload-sync behavior out of web.js.
Kept web.js focused on wiring and server startup.
Fixed screen playlist reassignment so changing a screen’s playlist now triggers a refresh.
Fixed single-slide playlist refresh behavior so updates do not get stuck behind the current slide.
Player changes:

Split websocket/runtime handling into runtime.js.
Split playlist assembly and revision hashing into playlist.js.
Split onboarding and player HTTP routes into dedicated modules.
Split render utilities and template loading into render-helpers.js.
Kept player.js mostly as startup/orchestration.
Validation:

Rebuilt both services with Docker Compose.
Smoke-checked web and player routes after the refactor.
Verified get_errors was clean on the touched modules.
This commit is contained in:
2026-07-20 23:58:27 +01:00
parent 480ccdbe9c
commit 2ea8d389fa
321 changed files with 12687 additions and 7080 deletions
+50 -28
View File
@@ -5,35 +5,57 @@
</div>
</div>
<div class="card account-card">
<form method="post" action="/admin/account/name" class="account-form account-form--name">
<label>
Display name
<input type="text" name="name" value="{{name}}" autocomplete="name" required />
</label>
<div class="actions">
<button type="submit">Save name</button>
<div class="row g-4">
<div class="col-12 col-xl-6">
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<h3 class="card-title">Display name</h3>
</div>
<form id="account-name-form" method="post" action="/admin/account/name" data-async-save data-async-save-close-url="{{returnUrl}}">
<input type="hidden" name="return_url" value="{{returnUrl}}" />
<div class="card-body">
<div class="mb-3">
<input id="account-name" type="text" name="name" class="form-control" value="{{name}}" autocomplete="name" required />
</div>
</div>
<div class="card-footer d-flex justify-content-end">
<div class="btn-group" role="group" aria-label="Display name actions">
{{{saveActionButtons formId="account-name-form" saveLabel="Save" saveAndCloseLabel="Save and Close" saveAndCloseValue="close" showSaveAndNew=false}}}
<a class="btn btn-warning" href="/admin" data-confirm-unsaved="You have unsaved changes. Leave this page?">Cancel</a>
</div>
</div>
</form>
</div>
</form>
</div>
</div>
<div class="card account-card">
<form method="post" action="/admin/account/password" class="account-form">
<label>
Current password
<input type="password" name="current_password" autocomplete="current-password" required />
</label>
<label>
New password
<input type="password" name="new_password" autocomplete="new-password" minlength="8" required />
</label>
<label>
Confirm new password
<input type="password" name="confirm_password" autocomplete="new-password" minlength="8" required />
</label>
<div class="actions">
<button type="submit">Update password</button>
<a class="button-link secondary" href="/admin">Back to dashboard</a>
<div class="col-12 col-xl-6">
<div class="card card-outline card-warning admin-form-card h-100">
<div class="card-header">
<h3 class="card-title">Password</h3>
</div>
<form id="account-password-form" method="post" action="/admin/account/password" data-async-save data-async-save-close-url="{{returnUrl}}">
<input type="hidden" name="return_url" value="{{returnUrl}}" />
<div class="card-body">
<div class="mb-3">
<label for="account-current-password" class="form-label">Current password</label>
<input id="account-current-password" type="password" name="current_password" class="form-control" autocomplete="current-password" required />
</div>
<div class="mb-3">
<label for="account-new-password" class="form-label">New password</label>
<input id="account-new-password" type="password" name="new_password" class="form-control" autocomplete="new-password" minlength="8" required />
</div>
<div class="mb-0">
<label for="account-confirm-password" class="form-label">Confirm new password</label>
<input id="account-confirm-password" type="password" name="confirm_password" class="form-control" autocomplete="new-password" minlength="8" required />
</div>
</div>
<div class="card-footer d-flex justify-content-end">
<div class="btn-group" role="group" aria-label="Password actions">
{{{saveActionButtons formId="account-password-form" saveLabel="Save" saveAndCloseLabel="Save and Close" saveAndCloseValue="close" showSaveAndNew=false}}}
<a class="btn btn-warning" href="/admin" data-confirm-unsaved="You have unsaved changes. Leave this page?">Cancel</a>
</div>
</div>
</form>
</div>
</form>
</div>
</div>