release: v2.11.2
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 2m0s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 31s

This commit is contained in:
2026-09-05 18:14:38 +01:00
parent 7fec2154e0
commit c4ae69d25f
40 changed files with 314 additions and 352 deletions
+4 -4
View File
@@ -8,7 +8,7 @@
<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">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Account details</h3>
</div>
<form id="account-profile-form" method="post" action="/account/profile" autocomplete="off" data-async-save data-async-save-refresh-page="true">
@@ -36,7 +36,7 @@
{{#if allowUserSessionRevocation}}
<div class="card card-outline card-secondary admin-form-card mt-3">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Active sessions</h3>
</div>
<div class="card-body">
@@ -74,7 +74,7 @@
<div class="col-12 col-xl-6">
<div class="card card-outline card-warning admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Password</h3>
</div>
<form id="account-password-form" method="post" action="/account/password" autocomplete="off" data-async-save data-async-save-refresh-page="true">
@@ -93,7 +93,7 @@
</form>
</div>
<div class="card card-outline card-secondary admin-form-card mt-3">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Confirmation</h3>
</div>
<div class="card-body">
@@ -11,7 +11,7 @@
<div class="col-12">
<form id="api-source-form" method="post" action="{{formAction}}" {{{formAttrs}}}>
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Connection</h3>
</div>
<div class="card-body">
@@ -89,7 +89,7 @@
</div>
</div>
<div class="card card-outline card-info admin-form-card mt-3 overflow-hidden api-source-auth-card{{#if isEdit}} collapsed-card{{/if}}" data-api-source-auth-card hidden>
<div class="card-header d-flex align-items-center">
<div class="card-header bg-body-tertiary d-flex align-items-center">
<h3 class="card-title mb-0">Authentication</h3>
<div class="card-tools d-flex align-items-center ms-auto me-0 flex-shrink-0">
<button type="button" class="btn btn-tool p-0 text-body-secondary" data-lte-toggle="card-collapse" aria-label="Toggle authentication settings" title="Toggle authentication settings">
@@ -176,7 +176,7 @@
</div>
<div class="col-12">
<div class="card card-outline card-secondary api-source-response-card" id="api-source-response-panel">
<div class="card-header d-flex align-items-center">
<div class="card-header bg-body-tertiary d-flex align-items-center">
<h3 class="card-title mb-0">Latest response</h3>
{{#if lastResponseJson}}
<div class="btn-group btn-group-sm ms-auto" role="group" aria-label="JSON tree actions">
@@ -7,7 +7,7 @@
<form id="rss-feed-form" method="post" action="{{formAction}}" {{{formAttrs}}}>
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">RSS feed details</h3>
</div>
<div class="card-body">
@@ -47,7 +47,7 @@
{{#if isEdit}}<form id="rss-feed-toggle-form" method="post" action="/data-sources/rss-feeds/{{rssFeed.id}}" data-async-command><input type="hidden" name="data_source_action" value="toggle" /></form>{{/if}}
<div class="card card-outline card-secondary admin-form-card mt-4">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Latest items</h3>
</div>
<div class="card-body">
@@ -7,7 +7,7 @@
<form id="timetable-group-form" method="post" action="{{formAction}}" {{{formAttrs}}}>
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Timetable group details</h3>
</div>
<div class="card-body d-grid gap-4 pb-0">
@@ -42,7 +42,7 @@
</div>
<div class="card card-outline card-secondary admin-form-card mt-4">
<div class="card-header d-flex align-items-center">
<div class="card-header bg-body-tertiary d-flex align-items-center">
<h3 class="card-title mb-0 flex-grow-1">Entries</h3>
<button type="button" class="btn btn-primary btn-sm ms-auto" data-add-timetable-entry>Add entry</button>
</div>
+1 -1
View File
@@ -5,7 +5,7 @@
<div class="col-12 col-xl-7">
<form id="weather-location-form" method="post" action="{{formAction}}" {{{formAttrs}}}>
<div class="card card-outline card-primary admin-form-card">
<div class="card-header"><h3 class="card-title">Weather location details</h3></div>
<div class="card-header bg-body-tertiary"><h3 class="card-title">Weather location details</h3></div>
<div class="card-body">
<div class="mb-3"><label for="weather-name" class="form-label">Name</label><input id="weather-name" name="name" class="form-control" value="{{weatherLocation.name}}" maxlength="255" required /></div>
<div class="mb-3 position-relative"><label for="weather-label" class="form-label">Location</label><input id="weather-label" name="location_label" class="form-control" value="{{weatherLocation.location_label}}" maxlength="255" placeholder="Start typing a town, city, or postcode" autocomplete="off" required /><div id="weather-location-results" class="list-group position-absolute w-100 d-none" style="z-index: 10;"></div><div class="form-text">Choose a result to fill the coordinates and timezone automatically.</div></div>
+2 -2
View File
@@ -8,8 +8,8 @@
<div class="row justify-content-center">
<div class="col-12 col-lg-7 col-xl-6">
<div class="card card-outline card-primary admin-form-card onboarding-pairing-card" id="onboarding-pair-card">
<div class="card-header">
<h3 class="card-title">Screen setup</h3>
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Screen setup</h3>
</div>
<form id="onboarding-pair-form" method="post" action="/pairing" novalidate>
<div class="card-body">
+1 -1
View File
@@ -46,7 +46,7 @@
<td><div class="fw-semibold text-capitalize">{{eventLabel}}</div><div class="text-muted small">{{category}}</div></td>
<td>{{actorLabel}}</td>
<td>{{targetLabelDisplay}}</td>
<td><div>{{ip_address}}</div><div class="text-muted small text-break">{{user_agent}}</div></td>
<td><div>{{ip_address}}</div><div class="text-muted small text-break">{{userAgentLabel}}</div></td>
<td class="text-break">
{{#if auditDetailView.hasChanges}}
<div class="audit-change-list">
+3 -3
View File
@@ -12,7 +12,7 @@
<div class="row g-3">
<div class="col-12 col-xl-4 d-flex flex-column gap-4">
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Role details</h3>
</div>
<div class="card-body">
@@ -33,7 +33,7 @@
</div>
<div class="card card-outline card-secondary admin-form-card" data-table-search-container data-table-pagination-card>
<div class="card-header d-flex flex-wrap align-items-center justify-content-between">
<div class="card-header bg-body-tertiary d-flex flex-wrap align-items-center justify-content-between">
<h3 class="card-title">Users</h3>
<div class="input-group input-group-sm flex-shrink-1 ms-auto table-search-group" style="width: min(14rem, 100%);">
<span class="input-group-text" role="button" tabindex="0" aria-label="Search" data-table-search-toggle><i class="bi bi-search"></i></span>
@@ -82,7 +82,7 @@
<div class="col-12 col-xl-8 d-flex flex-column gap-4">
<div class="card card-outline card-secondary admin-form-card overflow-hidden">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Permissions</h3>
</div>
<div class="card-body p-0">
+7 -4
View File
@@ -282,6 +282,9 @@
<div class="col-12 col-md-4"><label class="form-label" for="settings-smtp-password">SMTP password</label><input id="settings-smtp-password" name="smtp_password" type="password" class="form-control" placeholder="{{#if mediaSettings.smtpConfigured}}Leave unchanged{{/if}}"></div>
<div class="col-12 col-md-6"><label class="form-label" for="settings-from-address">From address</label><input id="settings-from-address" name="from_address" type="email" class="form-control" value="{{mediaSettings.emailFromAddress}}"></div>
<div class="col-12 col-md-6"><label class="form-label" for="settings-from-name">From name</label><input id="settings-from-name" name="from_name" type="text" class="form-control" value="{{mediaSettings.emailFromName}}"></div>
<div class="col-12 col-md-4"><label class="form-label" for="settings-verification-expiry">Verification expiry</label><div class="input-group"><input id="settings-verification-expiry" name="verification_expiry_minutes" type="number" class="form-control" min="1" max="10080" value="{{mediaSettings.verificationExpiryMinutes}}"><span class="input-group-text">minutes</span></div></div>
<div class="col-12 col-md-4"><label class="form-label" for="settings-reset-expiry">Password reset expiry</label><div class="input-group"><input id="settings-reset-expiry" name="reset_expiry_minutes" type="number" class="form-control" min="1" max="10080" value="{{mediaSettings.resetExpiryMinutes}}"><span class="input-group-text">minutes</span></div></div>
<div class="col-12 col-md-4"><label class="form-label" for="settings-invitation-expiry">Invitation expiry</label><div class="input-group"><input id="settings-invitation-expiry" name="invitation_expiry_hours" type="number" class="form-control" min="1" max="720" value="{{mediaSettings.invitationExpiryHours}}"><span class="input-group-text">hours</span></div></div>
</div></div>
<div class="card-footer d-flex align-items-center">
{{#if (hasPermission currentUser 'system-settings.update')}}
@@ -300,7 +303,7 @@
<div id="email-templates" class="card settings-section-card" data-settings-section hidden>
<div class="card-header"><h3 class="h5 mb-1 fw-semibold"><i class="bi bi-envelope-paper me-2 text-primary" aria-hidden="true"></i>Email templates</h3><p class="text-muted small mb-0">Customize the messages sent for email verification and password resets.</p></div>
<div class="card-body">
<div data-email-preview-user data-username="{{currentUser.username}}" data-display-name="{{currentUser.name}}" data-email="{{currentUser.email}}" hidden></div>
<div data-email-preview-user data-username="{{currentUser.username}}" data-display-name="{{currentUser.name}}" data-email="{{currentUser.email}}" data-verification-expiry="{{mediaSettings.verificationExpiryMinutes}}" data-reset-expiry="{{mediaSettings.resetExpiryMinutes}}" data-invitation-expiry="{{mediaSettings.invitationExpiryHours}}" hidden></div>
<div class="email-template-editor" data-email-template-editor>
<div class="row g-4 align-items-start">
<div class="col-12 col-lg-6">
@@ -314,7 +317,7 @@
<div class="col-12 col-md-8"><label class="form-label" for="settings-verification-button-text">Button text</label><input id="settings-verification-button-text" name="verification_button_text" type="text" class="form-control" value="{{mediaSettings.verificationButtonText}}" maxlength="120" data-email-template-button-text></div>
<div class="col-12 col-md-4"><label class="form-label" for="settings-verification-alignment">Alignment</label><select id="settings-verification-alignment" name="verification_button_alignment" class="form-select" data-email-template-alignment><option value="left" {{#if (eq mediaSettings.verificationButtonAlignment 'left')}}selected{{/if}}>Left</option><option value="center" {{#if (eq mediaSettings.verificationButtonAlignment 'center')}}selected{{/if}}>Center</option><option value="right" {{#if (eq mediaSettings.verificationButtonAlignment 'right')}}selected{{/if}}>Right</option></select></div>
</div>
<div class="form-text">Use <code>[[action_button]]</code> for a button or <code>[[url]]</code> for the verification link. Available values: <code>[[username]]</code>, <code>[[display_name]]</code>, <code>[[email]]</code>.</div>
<div class="form-text">Use <code>[[action_button]]</code> for a button or <code>[[url]]</code> for the verification link. Available values: <code>[[username]]</code>, <code>[[display_name]]</code>, <code>[[email]]</code>, <code>[[expiry_time]]</code>.</div>
</div>
<div class="col-12 col-lg-6">
<div class="email-template-preview" data-email-template-preview aria-label="Email verification preview"></div>
@@ -335,7 +338,7 @@
<div class="col-12 col-md-8"><label class="form-label" for="settings-reset-button-text">Button text</label><input id="settings-reset-button-text" name="reset_button_text" type="text" class="form-control" value="{{mediaSettings.resetButtonText}}" maxlength="120" data-email-template-button-text></div>
<div class="col-12 col-md-4"><label class="form-label" for="settings-reset-alignment">Alignment</label><select id="settings-reset-alignment" name="reset_button_alignment" class="form-select" data-email-template-alignment><option value="left" {{#if (eq mediaSettings.resetButtonAlignment 'left')}}selected{{/if}}>Left</option><option value="center" {{#if (eq mediaSettings.resetButtonAlignment 'center')}}selected{{/if}}>Center</option><option value="right" {{#if (eq mediaSettings.resetButtonAlignment 'right')}}selected{{/if}}>Right</option></select></div>
</div>
<div class="form-text">Use <code>[[action_button]]</code> for a button or <code>[[url]]</code> for the reset link. Available values: <code>[[username]]</code>, <code>[[display_name]]</code>, <code>[[email]]</code>.</div>
<div class="form-text">Use <code>[[action_button]]</code> for a button or <code>[[url]]</code> for the reset link. Available values: <code>[[username]]</code>, <code>[[display_name]]</code>, <code>[[email]]</code>, <code>[[expiry_time]]</code>.</div>
</div>
<div class="col-12 col-lg-6">
<div class="email-template-preview" data-email-template-preview aria-label="Password reset preview"></div>
@@ -356,7 +359,7 @@
<div class="col-12 col-md-8"><label class="form-label" for="settings-invitation-button-text">Button text</label><input id="settings-invitation-button-text" name="invitation_button_text" type="text" class="form-control" value="{{mediaSettings.invitationButtonText}}" maxlength="120" data-email-template-button-text></div>
<div class="col-12 col-md-4"><label class="form-label" for="settings-invitation-alignment">Alignment</label><select id="settings-invitation-alignment" name="invitation_button_alignment" class="form-select" data-email-template-alignment><option value="left" {{#if (eq mediaSettings.invitationButtonAlignment 'left')}}selected{{/if}}>Left</option><option value="center" {{#if (eq mediaSettings.invitationButtonAlignment 'center')}}selected{{/if}}>Center</option><option value="right" {{#if (eq mediaSettings.invitationButtonAlignment 'right')}}selected{{/if}}>Right</option></select></div>
</div>
<div class="form-text">Use <code>[[action_button]]</code> for a button or <code>[[url]]</code> for the invitation link. Available values: <code>[[display_name]]</code>, <code>[[email]]</code>.</div>
<div class="form-text">Use <code>[[action_button]]</code> for a button or <code>[[url]]</code> for the invitation link. Available values: <code>[[display_name]]</code>, <code>[[email]]</code>, <code>[[expiry_time]]</code>.</div>
</div>
<div class="col-12 col-lg-6"><div class="email-template-preview" data-email-template-preview aria-label="User invitation preview"></div></div>
</div>
+4 -4
View File
@@ -9,7 +9,7 @@
<div class="row g-3">
<div class="col-12 col-xl-4">
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">{{#if isEdit}}Profile{{else}}User details{{/if}}</h3>
</div>
<div class="card-body">
@@ -55,7 +55,7 @@
</div>
<div class="card card-outline card-warning admin-form-card mt-3">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">{{#if isEdit}}Reset password{{else}}Password{{/if}}</h3>
</div>
<div class="card-body">
@@ -79,7 +79,7 @@
<div class="col-12 col-xl-8">
<div class="card card-outline card-secondary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Roles</h3>
</div>
<div class="card-body">
@@ -111,7 +111,7 @@
{{#if isEdit}}
<div class="card card-outline card-secondary admin-form-card mt-3">
<div class="card-header d-flex align-items-center justify-content-between">
<div class="card-header bg-body-tertiary d-flex align-items-center justify-content-between">
<h3 class="card-title">Active sessions</h3>
{{#if sessions.length}}
<form method="post" action="/settings/users/{{user.id}}/sessions/revoke-all" class="ms-auto flex-shrink-0" data-confirm-message="Sign out all sessions for this user?">
+2 -2
View File
@@ -9,7 +9,7 @@
<div class="row g-3">
<div class="col-12 col-xl-4">
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Invitation details</h3>
</div>
<div class="card-body">
@@ -36,7 +36,7 @@
<div class="col-12 col-xl-8">
<div class="card card-outline card-secondary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Roles</h3>
</div>
<div class="card-body">
+2 -2
View File
@@ -9,7 +9,7 @@
<div class="row g-4 mb-4">
<div class="col-12 col-xl-7">
<div class="card card-outline card-primary admin-form-card h-100 mb-0">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Content</h3>
</div>
<div class="card-body">
@@ -122,7 +122,7 @@
</div>
</div>
<div class="card card-outline card-secondary admin-form-card mb-4">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Screen Groups</h3>
</div>
<div class="card-body">
+1 -1
View File
@@ -7,7 +7,7 @@
<form id="canvas-size-form" method="post" action="{{formAction}}" {{{formAttrs}}}>
<div class="card card-outline card-primary admin-form-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Canvas size details</h3>
</div>
<div class="card-body">
+3 -3
View File
@@ -8,7 +8,7 @@
<div class="row g-4 mb-4 align-items-stretch">
<div class="col-12 col-lg-6">
<div class="card card-outline card-primary admin-form-card h-100">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Playlist details</h3>
</div>
<form id="playlist-edit-form" method="post" action="{{formAction}}" {{{formAttrs}}}>
@@ -38,7 +38,7 @@
</div>
<div class="col-12 col-lg-6">
<div class="card card-outline card-light h-100 mb-0">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h4 class="card-title">Options</h4>
</div>
<div class="card-body py-3">
@@ -58,7 +58,7 @@
<div class="row g-4 mb-4">
<div class="col-12">
<div class="card card-outline card-secondary mb-0">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Playlist items</h3>
<div class="card-tools d-flex flex-nowrap align-items-center gap-2">
<button type="button" class="btn btn-primary btn-sm" id="playlist-open-slide-modal" data-bs-toggle="modal" data-bs-target="#playlist-add-slide-modal" {{#unless playlistCanvasId}}disabled{{/unless}}>Add slide</button>
+1 -1
View File
@@ -8,7 +8,7 @@
<div class="row g-4">
<div class="col-12">
<div class="card card-outline card-primary admin-form-card h-100">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Screen group details</h3>
</div>
<form id="screen-form" method="post" action="{{formAction}}" {{{formAttrs}}}>
+2 -2
View File
@@ -9,7 +9,7 @@
<link rel="stylesheet" href="/assets/vendor/cropperjs/cropper.min.css" />
<form method="post" action="{{action}}" enctype="multipart/form-data" id="slide-form" class="slide-form-stack" {{{formAttrs}}}>
<div class="card card-outline card-primary admin-form-card slide-template-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Slide details</h3>
</div>
<div class="card-body">
@@ -54,7 +54,7 @@
</div>
<aside class="card card-outline card-secondary admin-form-card slide-preview-card">
<div class="card-header d-flex align-items-center justify-content-between">
<div class="card-header bg-body-tertiary d-flex align-items-center justify-content-between">
<div class="slide-preview-header">
<h3>Preview</h3>
</div>
+5 -5
View File
@@ -16,7 +16,7 @@
<div class="template-designer-layout">
<div class="card card-outline card-secondary admin-form-card mb-3">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Designer</h3>
</div>
<div class="card-body">
@@ -45,7 +45,7 @@
</div>
</div>
<div class="card card-outline card-info admin-form-card region-info-card mb-3">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<div>
<h3 class="card-title">Region information</h3>
</div>
@@ -65,7 +65,7 @@
<div class="row g-4 mb-4 align-items-stretch">
<div class="col-12 col-xl-4">
<div class="card card-outline card-primary admin-form-card h-100 template-details-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Template details</h3>
</div>
<div class="card-body">
@@ -93,7 +93,7 @@
</div>
<div class="col-12 col-xl-8">
<div class="card card-outline card-primary admin-form-card h-100 template-options-card">
<div class="card-header">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Options</h3>
</div>
<div class="card-body">
@@ -154,7 +154,7 @@
<template id="region-card-template">
<div class="card card-outline card-secondary admin-form-card region-item">
<div class="card-header template-field-head d-flex align-items-center flex-nowrap gap-2"><strong class="flex-grow-1 text-truncate" data-region-title>Region</strong><span class="chip ms-auto" data-region-chip>Text</span></div>
<div class="card-header bg-body-tertiary template-field-head d-flex align-items-center flex-nowrap gap-2"><strong class="flex-grow-1 text-truncate" data-region-title>Region</strong><span class="chip ms-auto" data-region-chip>Text</span></div>
<div class="card-body p-3 d-grid gap-3 pb-0">
<div class="region-field-grid region-field-grid--identity">
<label>Region name<input class="form-control" name="region_name[]" value="" maxlength="64" data-limit-text-length placeholder="type_1" required /></label>