Release v2.2.2
This commit is contained in:
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## 2.2.2 - 2026-08-01
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The theme bootstrap now resolves saved `auto` to an actual dark or light value on first paint, so explicit dark mode no longer flashes white while the page loads.
|
||||||
|
- The shared app header is now sticky so the top navigation stays visible while scrolling.
|
||||||
|
|
||||||
## 2.2.1 - 2026-08-01
|
## 2.2.1 - 2026-08-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
+254
-3
@@ -101,6 +101,11 @@ Primary keys are `id` unless noted otherwise. Timestamps are stored as `created_
|
|||||||
- `d_screens` - screen records and playlist/player assignment.
|
- `d_screens` - screen records and playlist/player assignment.
|
||||||
- `d_onboarding_devices` - device-to-screen bindings and onboarded client names.
|
- `d_onboarding_devices` - device-to-screen bindings and onboarded client names.
|
||||||
|
|
||||||
|
## Announcements
|
||||||
|
|
||||||
|
- `d_announcements` - announcement content and display metadata.
|
||||||
|
- `d_announcement_screens` - announcement-to-screen assignments.
|
||||||
|
|
||||||
### `d_players`
|
### `d_players`
|
||||||
|
|
||||||
- `device_id`, `public_base_url`, `internal_base_url`, `last_seen_at`, `created_at`, `modified_at`
|
- `device_id`, `public_base_url`, `internal_base_url`, `last_seen_at`, `created_at`, `modified_at`
|
||||||
@@ -123,6 +128,19 @@ Primary keys are `id` unless noted otherwise. Timestamps are stored as `created_
|
|||||||
- Foreign key:
|
- Foreign key:
|
||||||
- `screen_id` -> `d_screens.id` with `ON DELETE SET NULL`
|
- `screen_id` -> `d_screens.id` with `ON DELETE SET NULL`
|
||||||
|
|
||||||
|
### `d_announcements`
|
||||||
|
|
||||||
|
- `id`, `message`, `short_label`, `announcement_type`, `color_key`, `icon_key`, `duration_seconds`, `expires_at`, `created_at`, `created_by`, `modified_at`, `modified_by`
|
||||||
|
- `announcement_type` defaults to `lower-third`.
|
||||||
|
|
||||||
|
### `d_announcement_screens`
|
||||||
|
|
||||||
|
- `announcement_id`, `screen_id`, `created_at`, `created_by`, `modified_at`, `modified_by`
|
||||||
|
- Foreign keys:
|
||||||
|
- `announcement_id` -> `d_announcements.id` with `ON DELETE CASCADE`
|
||||||
|
- `screen_id` -> `d_screens.id` with `ON DELETE CASCADE`
|
||||||
|
- Composite primary key: `(announcement_id, screen_id)`
|
||||||
|
|
||||||
## Onboarding
|
## Onboarding
|
||||||
|
|
||||||
- The onboarding flow uses `d_onboarding_devices` to bind a device to a screen and persist the client name.
|
- The onboarding flow uses `d_onboarding_devices` to bind a device to a screen and persist the client name.
|
||||||
@@ -166,6 +184,240 @@ Primary keys are `id` unless noted otherwise. Timestamps are stored as `created_
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
erDiagram
|
erDiagram
|
||||||
|
A_USERS {
|
||||||
|
INT id
|
||||||
|
VARCHAR name
|
||||||
|
VARCHAR username
|
||||||
|
CHAR password_hash
|
||||||
|
VARCHAR password_salt
|
||||||
|
INT password_iterations
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
A_ROLES {
|
||||||
|
INT id
|
||||||
|
VARCHAR role_key
|
||||||
|
VARCHAR name
|
||||||
|
TEXT description
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
A_PERMISSIONS {
|
||||||
|
INT id
|
||||||
|
VARCHAR permission_key
|
||||||
|
VARCHAR name
|
||||||
|
VARCHAR section_name
|
||||||
|
TEXT description
|
||||||
|
TIMESTAMP created_at
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
}
|
||||||
|
A_ROLE_PERMISSIONS {
|
||||||
|
INT role_id
|
||||||
|
INT permission_id
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
A_USER_ROLES {
|
||||||
|
INT user_id
|
||||||
|
INT role_id
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
A_SESSIONS {
|
||||||
|
CHAR session_hash
|
||||||
|
INT user_id
|
||||||
|
DATETIME expires_at
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP last_used_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
C_CANVAS_SIZES {
|
||||||
|
INT id
|
||||||
|
VARCHAR name
|
||||||
|
INT width
|
||||||
|
INT height
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
C_PLAYLISTS {
|
||||||
|
INT id
|
||||||
|
VARCHAR name
|
||||||
|
TINYINT fade_between_slides
|
||||||
|
TINYINT skip_unavailable_rtmp
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
C_TEMPLATES {
|
||||||
|
INT id
|
||||||
|
VARCHAR name
|
||||||
|
INT canvas_size_id
|
||||||
|
VARCHAR background_image_path
|
||||||
|
VARCHAR background_color
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
C_TEMPLATE_REGIONS {
|
||||||
|
INT id
|
||||||
|
INT template_id
|
||||||
|
VARCHAR region_key
|
||||||
|
VARCHAR region_type
|
||||||
|
VARCHAR label
|
||||||
|
VARCHAR font_family
|
||||||
|
VARCHAR lock_ratio
|
||||||
|
INT x
|
||||||
|
INT y
|
||||||
|
INT width
|
||||||
|
INT height
|
||||||
|
INT z_index
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
C_SLIDES {
|
||||||
|
INT id
|
||||||
|
VARCHAR title
|
||||||
|
INT template_id
|
||||||
|
JSON content_json
|
||||||
|
VARCHAR thumbnail_path
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
C_PLAYLIST_SLIDES {
|
||||||
|
INT id
|
||||||
|
INT playlist_id
|
||||||
|
INT slide_id
|
||||||
|
INT position
|
||||||
|
DECIMAL duration_seconds
|
||||||
|
TINYINT use_video_duration
|
||||||
|
VARCHAR schedule_mode
|
||||||
|
DATETIME schedule_start_datetime
|
||||||
|
DATETIME schedule_end_datetime
|
||||||
|
TIME schedule_start_time
|
||||||
|
TIME schedule_end_time
|
||||||
|
JSON schedule_days_json
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
D_PLAYERS {
|
||||||
|
INT device_id
|
||||||
|
VARCHAR public_base_url
|
||||||
|
VARCHAR internal_base_url
|
||||||
|
TIMESTAMP last_seen_at
|
||||||
|
TIMESTAMP created_at
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
}
|
||||||
|
D_SCREENS {
|
||||||
|
INT id
|
||||||
|
VARCHAR name
|
||||||
|
VARCHAR slug
|
||||||
|
INT playlist_id
|
||||||
|
INT player_id
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
D_ONBOARDING_DEVICES {
|
||||||
|
VARCHAR device_id
|
||||||
|
VARCHAR client_name
|
||||||
|
INT screen_id
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
D_ANNOUNCEMENTS {
|
||||||
|
INT id
|
||||||
|
TEXT message
|
||||||
|
VARCHAR short_label
|
||||||
|
VARCHAR announcement_type
|
||||||
|
VARCHAR color_key
|
||||||
|
VARCHAR icon_key
|
||||||
|
INT duration_seconds
|
||||||
|
TIMESTAMP expires_at
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
D_ANNOUNCEMENT_SCREENS {
|
||||||
|
INT announcement_id
|
||||||
|
INT screen_id
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
I_RSS_FEEDS {
|
||||||
|
INT id
|
||||||
|
VARCHAR name
|
||||||
|
VARCHAR feed_url
|
||||||
|
INT update_interval_value
|
||||||
|
VARCHAR update_interval_unit
|
||||||
|
INT item_limit
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
I_RSS_FEED_ITEMS {
|
||||||
|
INT id
|
||||||
|
INT rss_feed_id
|
||||||
|
INT position
|
||||||
|
MEDIUMTEXT item_json
|
||||||
|
TIMESTAMP created_at
|
||||||
|
INT created_by
|
||||||
|
TIMESTAMP modified_at
|
||||||
|
INT modified_by
|
||||||
|
}
|
||||||
|
I_API_SOURCES {
|
||||||
|
INT id
|
||||||
|
VARCHAR name
|
||||||
|
VARCHAR api_url
|
||||||
|
INT update_interval_value
|
||||||
|
VARCHAR update_interval_unit
|
||||||
|
TIMESTAMP last_pulled_at
|
||||||
|
MEDIUMTEXT last_pull_error
|
||||||
|
INT last_response_status
|
||||||
|
VARCHAR last_response_content_type
|
||||||
|
MEDIUMTEXT last_response_json
|
||||||
|
}
|
||||||
|
O_BACKGROUND_TASKS {
|
||||||
|
BIGINT id
|
||||||
|
VARCHAR task_key
|
||||||
|
VARCHAR task_type
|
||||||
|
VARCHAR title
|
||||||
|
VARCHAR category
|
||||||
|
VARCHAR status
|
||||||
|
MEDIUMTEXT payload_json
|
||||||
|
MEDIUMTEXT metadata_json
|
||||||
|
INT attempts
|
||||||
|
TIMESTAMP created_at
|
||||||
|
TIMESTAMP started_at
|
||||||
|
TIMESTAMP finished_at
|
||||||
|
MEDIUMTEXT error_message
|
||||||
|
}
|
||||||
|
|
||||||
A_USERS ||--o{ A_USER_ROLES : has
|
A_USERS ||--o{ A_USER_ROLES : has
|
||||||
A_ROLES ||--o{ A_USER_ROLES : assigned_to
|
A_ROLES ||--o{ A_USER_ROLES : assigned_to
|
||||||
A_ROLES ||--o{ A_ROLE_PERMISSIONS : has
|
A_ROLES ||--o{ A_ROLE_PERMISSIONS : has
|
||||||
@@ -181,9 +433,8 @@ erDiagram
|
|||||||
D_PLAYERS ||--o{ D_SCREENS : assigned_to
|
D_PLAYERS ||--o{ D_SCREENS : assigned_to
|
||||||
C_PLAYLISTS ||--o{ D_SCREENS : uses
|
C_PLAYLISTS ||--o{ D_SCREENS : uses
|
||||||
D_SCREENS ||--o{ D_ONBOARDING_DEVICES : binds
|
D_SCREENS ||--o{ D_ONBOARDING_DEVICES : binds
|
||||||
|
D_ANNOUNCEMENTS ||--o{ D_ANNOUNCEMENT_SCREENS : targets
|
||||||
|
D_SCREENS ||--o{ D_ANNOUNCEMENT_SCREENS : receives
|
||||||
|
|
||||||
I_RSS_FEEDS ||--o{ I_RSS_FEED_ITEMS : caches
|
I_RSS_FEEDS ||--o{ I_RSS_FEED_ITEMS : caches
|
||||||
O_BACKGROUND_TASKS {
|
|
||||||
BIGINT id
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pulse-signage",
|
"name": "pulse-signage",
|
||||||
"version": "2.2.1",
|
"version": "2.2.2",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "Pulse Signage application with MySQL and media storage",
|
"description": "Pulse Signage application with MySQL and media storage",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -123,6 +123,11 @@
|
|||||||
--bs-navbar-nav-link-padding-x: 10px;
|
--bs-navbar-nav-link-padding-x: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-header {
|
||||||
|
top: 0;
|
||||||
|
z-index: 1030;
|
||||||
|
}
|
||||||
|
|
||||||
.app-sidebar {
|
.app-sidebar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
var storageKey = 'lte-theme';
|
var storageKey = 'lte-theme';
|
||||||
var theme = 'auto';
|
var theme = 'dark';
|
||||||
|
|
||||||
function getPreferredTheme() {
|
function getPreferredTheme() {
|
||||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
try {
|
try {
|
||||||
var storedTheme = window.localStorage.getItem(storageKey);
|
var storedTheme = window.localStorage.getItem(storageKey);
|
||||||
if (storedTheme === 'dark' || storedTheme === 'light' || storedTheme === 'auto') {
|
if (storedTheme === 'dark' || storedTheme === 'light' || storedTheme === 'auto') {
|
||||||
theme = storedTheme;
|
theme = storedTheme === 'auto' ? getPreferredTheme() : storedTheme;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
theme = 'auto';
|
theme = 'dark';
|
||||||
}
|
}
|
||||||
|
|
||||||
document.documentElement.dataset.bsTheme = theme;
|
document.documentElement.dataset.bsTheme = theme;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<div class="app-wrapper">
|
<div class="app-wrapper">
|
||||||
<div class="sidebar-overlay" aria-hidden="true"></div>
|
<div class="sidebar-overlay" aria-hidden="true"></div>
|
||||||
{{#unless hideFrameHeader}}
|
{{#unless hideFrameHeader}}
|
||||||
<nav class="app-header navbar navbar-expand bg-body">
|
<nav class="app-header sticky-top navbar navbar-expand bg-body">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<span class="navbar-text fw-semibold">
|
<span class="navbar-text fw-semibold">
|
||||||
{{title}}
|
{{title}}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="app-wrapper">
|
<div class="app-wrapper">
|
||||||
<div class="sidebar-overlay" aria-hidden="true"></div>
|
<div class="sidebar-overlay" aria-hidden="true"></div>
|
||||||
<nav class="app-header navbar navbar-expand bg-body">
|
<nav class="app-header sticky-top navbar navbar-expand bg-body">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
|||||||
Reference in New Issue
Block a user