233 lines
11 KiB
Handlebars
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}}
|