Files
pulse-signage/src/web/views/signage/dashboard/index.hbs
T
2026-08-08 23:15:04 +01:00

233 lines
11 KiB
Handlebars

<div class="page-header">
<div>
<h2>Dashboard</h2>
<p>Monitor screen groups and quick actions from one place.</p>
</div>
</div>
<section class="dashboard-hero card card-outline card-primary mb-4">
<div class="card-body dashboard-hero-body">
<div>
<span class="dashboard-hero-kicker">Live overview</span>
<h3 class="dashboard-hero-title">Keep the control surface focused on live state and actions.</h3>
<p class="dashboard-hero-copy">Use the cards below for the current totals, then open the screen group snapshot when you want a quick read on playlist assignment and live connections.</p>
{{#if primaryPlayerUrl}}
<div class="alert alert-info mb-0 mt-3 py-2">
<strong>Begin onboarding:</strong>
open <a href="{{primaryPlayerUrl}}" target="_blank" rel="noreferrer">{{primaryPlayerUrl}}</a>
on the public display to get started.
</div>
{{/if}}
</div>
<div class="dashboard-hero-stats">
{{#if (hasPermission currentUser "playlists.read")}}
<div class="dashboard-hero-stat">
<span class="dashboard-hero-stat-value">{{playlists.length}}</span>
<span class="dashboard-hero-stat-label">playlists</span>
</div>
{{/if}}
{{#if (hasPermission currentUser "screens.read")}}
<div class="dashboard-hero-stat">
<span class="dashboard-hero-stat-value">{{screens.length}}</span>
<span class="dashboard-hero-stat-label">screen groups</span>
</div>
{{/if}}
{{#if (hasPermission currentUser "clients.read")}}
<div class="dashboard-hero-stat">
<span id="dashboard-player-count" class="dashboard-hero-stat-value">{{connectedPlayersCount}}</span>
<span class="dashboard-hero-stat-label">players</span>
</div>
{{/if}}
</div>
</div>
</section>
{{#if (hasPermission currentUser "dashboard.allow")}}
<div class="row">
<div class="col-12 col-xl-8">
<div class="card card-outline card-primary dashboard-actions-card pb-4">
<div class="card-header">
<div class="dashboard-card-heading">
<h3 class="card-title">Quick actions</h3>
<p class="dashboard-card-subtitle">Send global commands without
leaving the overview.</p>
</div>
</div>
<div class="card-body">
<div class="dashboard-action-grid">
<form
method="post"
action="/commands"
class="dashboard-action-form"
data-confirm-message="Reload all connected clients?"
data-async-command
>
<input type="hidden" name="command" value="reload" />
<button
type="submit"
class="btn btn-danger dashboard-action-button"
id="dashboard-reload-all-button"
><i class="bi bi-arrow-repeat me-1" aria-hidden="true"></i>Reload all clients</button>
<span class="dashboard-action-help">Restart every connected player page.</span>
</form>
<form
method="post"
action="/commands"
class="dashboard-action-form"
data-confirm-message="Pause all connected clients?"
data-async-command
>
<input type="hidden" name="command" value="pause" />
<input type="hidden" name="paused" value="true" />
<button
type="submit"
class="btn btn-info dashboard-action-button"
id="dashboard-pause-all-button"
><i class="bi bi-pause-fill me-1" aria-hidden="true"></i>Pause all clients</button>
<span class="dashboard-action-help">Freeze playback on every connected player.</span>
</form>
<form
method="post"
action="/commands"
class="dashboard-action-form"
data-confirm-message="Blackout all connected clients?"
data-async-command
>
<input type="hidden" name="command" value="blackout" />
<input type="hidden" name="blackout" value="true" />
<button
type="submit"
class="btn btn-secondary dashboard-action-button"
id="dashboard-blackout-all-button"
><i class="bi bi-eye-slash me-1" aria-hidden="false"></i>Blackout
all clients</button>
<span class="dashboard-action-help">Blank active players
immediately.</span>
</form>
</div>
</div>
</div>
</div>
<div class="col-12 col-xl-4">
<div class="card card-outline card-secondary dashboard-launcher-card h-100 pb-4">
<div class="card-header">
<div class="dashboard-card-heading">
<h3 class="card-title">Kiosk launchers</h3>
<p class="dashboard-card-subtitle">Open the player base URL on a device for onboarding.</p>
</div>
</div>
<div class="card-body">
<div class="dashboard-launcher-row h-100">
<p class="mb-0 text-muted small dashboard-launcher-copy">Download the Windows or Linux launcher to start a browser in kiosk mode and open the correct player page for onboarding.</p>
<div class="dashboard-launcher-actions h-100">
<button type="button" class="btn btn-outline-secondary btn-lg d-inline-flex align-items-center justify-content-center dashboard-launcher-open-button h-100" data-bs-toggle="modal" data-bs-target="#dashboard-kiosk-launcher-modal">
<i class="bi bi-download" aria-hidden="true"></i>
<span></span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
{{#> modal-shell modalId="dashboard-kiosk-launcher-modal" modalLabelId="dashboard-kiosk-launcher-modal-label" modalDialogClass="modal-dialog-centered modal-lg"}}
<div class="modal-header">
<div>
<h2 class="modal-title fs-5" id="dashboard-kiosk-launcher-modal-label">Kiosk launcher downloads</h2>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body d-grid gap-4">
<div class="alert alert-info mb-0">
<p class="mb-2 fw-semibold">Kiosk mode is for dedicated signage screens.</p>
<ul class="mb-0 ps-3">
<li>The script looks for a supported browser on the device and launches the first one it finds.</li>
<li>The launcher opens the correct player page automatically, so no manual URL entry is needed.</li>
<li>It uses a kiosk-mode browser window, so the screen stays focused on signage instead of normal browsing.</li>
<li>If a browser is already open or open in the background, the launcher will bring it to the front, but not enter kiosk mode.</li>
<li>Exit with Alt+F4 on Windows or Linux.</li>
</ul>
<div class="mt-3 pt-3 border-top">
<p class="mb-0 text-muted small">These downloads are scripts, not applications: the Windows download is a .bat file and the Linux download is a .sh file.</p>
</div>
</div>
<div class="dashboard-kiosk-launcher-confirmation p-3 border rounded-3 bg-body-tertiary">
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" value="1" id="dashboard-kiosk-launcher-confirm" data-kiosk-launcher-confirm />
<label class="form-check-label fw-semibold fs-5" for="dashboard-kiosk-launcher-confirm">I Understand</label>
</div>
<p class="mb-0 mt-2 text-muted small">Check this box to enable the Windows and Linux downloads.</p>
</div>
<div class="d-grid gap-2">
<select class="form-select" id="dashboard-kiosk-launcher-player-select" data-kiosk-launcher-player-select>
<option value="">Select a player</option>
{{#each kioskPlayers}}
{{#if player_identifier}}
{{#if player_url}}
<option value="{{player_url}}" data-player-identifier="{{player_identifier}}">{{player_identifier}} - {{player_url}}</option>
{{/if}}
{{/if}}
{{/each}}
</select>
<p class="mb-0 text-muted small">The download will open the selected player's public URL when the kiosk starts.</p>
</div>
<div class="d-flex flex-column flex-sm-row gap-2">
<a class="btn btn-outline-primary btn-lg flex-fill disabled dashboard-kiosk-launcher-download" data-kiosk-launcher-download data-kiosk-launcher-download-base="/downloads/kiosk/pulse-signage-kiosk.bat" aria-disabled="true" tabindex="-1">
<i class="bi bi-windows me-2" aria-hidden="true"></i>
<span>Download for Windows</span>
</a>
<a class="btn btn-outline-secondary btn-lg flex-fill disabled dashboard-kiosk-launcher-download" data-kiosk-launcher-download data-kiosk-launcher-download-base="/downloads/kiosk/pulse-signage-kiosk.sh" aria-disabled="true" tabindex="-1">
<i class="bi bi-terminal me-2" aria-hidden="true"></i>
<span>Download for Linux</span>
</a>
</div>
</div>
{{/modal-shell}}
{{/if}}
{{#if (hasPermission currentUser "screens.read")}}
<div class="row">
<div class="col-12">
<div class="card card-outline card-secondary dashboard-screen-card-shell">
<div class="card-header dashboard-screen-card-header">
<div class="dashboard-card-heading">
<h3 class="card-title">Screen group snapshot</h3>
<p class="dashboard-card-subtitle">Playlist assignment and live connection state without the spreadsheet feel.</p>
</div>
<a class="btn btn-sm btn-primary" href="/screens">Manage screen groups</a>
</div>
<div class="card-body">
<div id="dashboard-screens-grid" class="dashboard-screen-grid">
{{#if screens.length}}
{{#each screens}}
<article class="dashboard-screen-tile" data-screen-key="{{id}}">
<div class="dashboard-screen-tile-top">
<div class="dashboard-screen-tile-text">
<h4 class="dashboard-screen-name">{{name}}</h4>
</div>
<span class="dashboard-screen-pill {{#if player_connection_count}}is-live{{else}}is-idle{{/if}}">
{{#if player_connection_count}}
{{player_connection_count}} live
{{else}}
No clients
{{/if}}
</span>
</div>
<dl class="dashboard-screen-meta">
<div>
<dt>Playlist</dt>
<dd>{{#if playlist_name}}{{playlist_name}}{{else}}Unassigned{{/if}}</dd>
</div>
</dl>
</article>
{{/each}}
{{else}}
<div class="empty dashboard-screen-empty">No screen groups yet.</div>
{{/if}}
</div>
</div>
</div>
</div>
</div>
{{/if}}