Update connection status indicator
This commit is contained in:
1 parent
2e603caeb6
commit
726a7fedc7
8 files changed
+254
-64
No files matched your search
@@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- The shared connection indicator names the connected path (Bridge or Player), shows the connected player count, uses blue when the service is online with no players, and uses one topology-neutral message when no services are connected. Status dots stay static and the last status is preserved across page navigation.
|
||||||
- Thumbnail previews use the shared region renderers so time/date and data placeholders match the editor preview.
|
- Thumbnail previews use the shared region renderers so time/date and data placeholders match the editor preview.
|
||||||
- Preview framing follows the application theme and preserves the modal's rounded corners.
|
- Preview framing follows the application theme and preserves the modal's rounded corners.
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -110,6 +110,7 @@ function createWebBootstrap(options) {
|
|||||||
pool: pool,
|
pool: pool,
|
||||||
common: common,
|
common: common,
|
||||||
thinClientBaseUrl: configuredBridgeInternalUrl,
|
thinClientBaseUrl: configuredBridgeInternalUrl,
|
||||||
|
playerServiceName: configuredBridgeInternalUrl ? 'Bridge' : 'Player',
|
||||||
playerSnapshotCache: playerSnapshotCache,
|
playerSnapshotCache: playerSnapshotCache,
|
||||||
playerSnapshotSockets: playerSnapshotSockets,
|
playerSnapshotSockets: playerSnapshotSockets,
|
||||||
ensurePlayerSnapshotSubscription: ensurePlayerSnapshotSubscription,
|
ensurePlayerSnapshotSubscription: ensurePlayerSnapshotSubscription,
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ function createDashboardStateService(options) {
|
|||||||
const pool = options && options.pool;
|
const pool = options && options.pool;
|
||||||
const common = options && options.common;
|
const common = options && options.common;
|
||||||
const connectedPlayerCountStaleSeconds = options && options.connectedPlayerCountStaleSeconds;
|
const connectedPlayerCountStaleSeconds = options && options.connectedPlayerCountStaleSeconds;
|
||||||
|
const playerServiceName = String(options && options.playerServiceName || 'Player');
|
||||||
const playerSnapshotCache = options && options.playerSnapshotCache;
|
const playerSnapshotCache = options && options.playerSnapshotCache;
|
||||||
const playerSnapshotSockets = options && options.playerSnapshotSockets;
|
const playerSnapshotSockets = options && options.playerSnapshotSockets;
|
||||||
const ensurePlayerSnapshotSubscription = options && options.ensurePlayerSnapshotSubscription;
|
const ensurePlayerSnapshotSubscription = options && options.ensurePlayerSnapshotSubscription;
|
||||||
@@ -189,6 +190,7 @@ function createDashboardStateService(options) {
|
|||||||
clients: clients,
|
clients: clients,
|
||||||
kioskPlayers: kioskPlayers,
|
kioskPlayers: kioskPlayers,
|
||||||
slides: data.slides || [],
|
slides: data.slides || [],
|
||||||
|
playerServiceName: playerServiceName,
|
||||||
playerServiceConnected: playerServiceConnected,
|
playerServiceConnected: playerServiceConnected,
|
||||||
connectedPlayersCount: connectedPlayersCount !== null ? connectedPlayersCount : 0,
|
connectedPlayersCount: connectedPlayersCount !== null ? connectedPlayersCount : 0,
|
||||||
connectedClientsCount: screens.reduce(function (total, screen) {
|
connectedClientsCount: screens.reduce(function (total, screen) {
|
||||||
|
|||||||
@@ -285,23 +285,14 @@
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
inset: -0.28rem;
|
|
||||||
border-radius: inherit;
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-dot--online {
|
.status-dot--online {
|
||||||
background: #28a745;
|
background: #28a745;
|
||||||
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.2);
|
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot--online::after {
|
.status-dot--idle {
|
||||||
background: rgba(40, 167, 69, 0.32);
|
background: #0d6efd;
|
||||||
animation: status-dot-pulse 1.8s ease-out infinite;
|
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot--offline {
|
.status-dot--offline {
|
||||||
@@ -314,28 +305,6 @@
|
|||||||
box-shadow: 0 0 0 0.2rem rgba(173, 181, 189, 0.18);
|
box-shadow: 0 0 0 0.2rem rgba(173, 181, 189, 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot--unknown::after {
|
|
||||||
background: rgba(173, 181, 189, 0.26);
|
|
||||||
animation: status-dot-pulse 1.8s ease-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes status-dot-pulse {
|
|
||||||
0% {
|
|
||||||
opacity: 0.55;
|
|
||||||
transform: scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
70% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(1.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(1.75);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Account menu */
|
/* Account menu */
|
||||||
|
|
||||||
.user-menu-avatar {
|
.user-menu-avatar {
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
(function () {
|
(function () {
|
||||||
function buildLivePlayerFeedLabel(connectedPlayersCount) {
|
var playerServiceName = 'Player';
|
||||||
var count = Number(connectedPlayersCount || 0);
|
|
||||||
if (count <= 0) {
|
|
||||||
return 'Player feed online - no players connected';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Live player feed - ' + count + ' player' + (count === 1 ? '' : 's') + ' connected';
|
function buildConnectingLabel() {
|
||||||
|
return playerServiceName === 'Bridge' ? 'Connecting to bridge' : 'Connecting to player service';
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSidebarStatus(status, label) {
|
function buildPlayerServiceLabel(connectedPlayersCount, serviceConnected) {
|
||||||
|
if (!serviceConnected) {
|
||||||
|
return 'No services connected';
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = Number(connectedPlayersCount || 0);
|
||||||
|
if (count <= 0) {
|
||||||
|
return playerServiceName + ' online - no players connected';
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerServiceName + ' online - ' + count + ' player' + (count === 1 ? '' : 's') + ' connected';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSidebarStatus(status, label, persist) {
|
||||||
var dot = document.getElementById('sidebar-status-dot');
|
var dot = document.getElementById('sidebar-status-dot');
|
||||||
var text = document.getElementById('sidebar-status-text');
|
var text = document.getElementById('sidebar-status-text');
|
||||||
var pill = document.getElementById('sidebar-status-pill');
|
var pill = document.getElementById('sidebar-status-pill');
|
||||||
@@ -16,18 +26,25 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var normalizedStatus = status === 'online' || status === 'offline' || status === 'unknown'
|
var normalizedStatus = status === 'online' || status === 'idle' || status === 'offline' || status === 'unknown'
|
||||||
? status
|
? status
|
||||||
: (status ? 'online' : 'offline');
|
: (status ? 'online' : 'offline');
|
||||||
var statusLabel = normalizedStatus === 'online'
|
var statusLabel = label;
|
||||||
? (label || 'Connected to player feed')
|
if (!statusLabel) {
|
||||||
: normalizedStatus === 'offline'
|
if (normalizedStatus === 'online') {
|
||||||
? 'Disconnected from player feed'
|
statusLabel = playerServiceName + ' online';
|
||||||
: (label || 'Connecting to player feed');
|
} else if (normalizedStatus === 'idle') {
|
||||||
var pillLabel = normalizedStatus === 'online' ? 'Connected' : normalizedStatus === 'offline' ? 'Disconnected' : 'Connecting';
|
statusLabel = playerServiceName + ' online - no players connected';
|
||||||
|
} else if (normalizedStatus === 'offline') {
|
||||||
|
statusLabel = 'No services connected';
|
||||||
|
} else {
|
||||||
|
statusLabel = buildConnectingLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var pillLabel = normalizedStatus === 'online' ? 'Connected' : normalizedStatus === 'idle' ? 'No players' : normalizedStatus === 'offline' ? 'Disconnected' : 'Connecting';
|
||||||
|
|
||||||
dot.classList.remove('status-dot--unknown', 'status-dot--online', 'status-dot--offline');
|
dot.classList.remove('status-dot--unknown', 'status-dot--online', 'status-dot--idle', 'status-dot--offline');
|
||||||
dot.classList.add(normalizedStatus === 'online' ? 'status-dot--online' : normalizedStatus === 'offline' ? 'status-dot--offline' : 'status-dot--unknown');
|
dot.classList.add(normalizedStatus === 'online' ? 'status-dot--online' : normalizedStatus === 'idle' ? 'status-dot--idle' : normalizedStatus === 'offline' ? 'status-dot--offline' : 'status-dot--unknown');
|
||||||
dot.setAttribute('aria-label', statusLabel);
|
dot.setAttribute('aria-label', statusLabel);
|
||||||
dot.setAttribute('title', statusLabel);
|
dot.setAttribute('title', statusLabel);
|
||||||
|
|
||||||
@@ -36,10 +53,41 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pill) {
|
if (pill) {
|
||||||
pill.classList.remove('status-pill--unknown', 'status-pill--online', 'status-pill--offline');
|
pill.classList.remove('status-pill--unknown', 'status-pill--online', 'status-pill--idle', 'status-pill--offline');
|
||||||
pill.classList.add(normalizedStatus === 'online' ? 'status-pill--online' : normalizedStatus === 'offline' ? 'status-pill--offline' : 'status-pill--unknown');
|
pill.classList.add(normalizedStatus === 'online' ? 'status-pill--online' : normalizedStatus === 'idle' ? 'status-pill--idle' : normalizedStatus === 'offline' ? 'status-pill--offline' : 'status-pill--unknown');
|
||||||
pill.textContent = pillLabel;
|
pill.textContent = pillLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (persist && window.sessionStorage) {
|
||||||
|
try {
|
||||||
|
window.sessionStorage.setItem('pulse-player-service-status-v2', JSON.stringify({ status: normalizedStatus, label: statusLabel, serviceName: playerServiceName }));
|
||||||
|
} catch (_error) {
|
||||||
|
// Storage may be unavailable in restricted browser contexts.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (persist) {
|
||||||
|
hasCachedStatus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasCachedStatus = false;
|
||||||
|
if (window.sessionStorage) {
|
||||||
|
try {
|
||||||
|
var cachedStatus = JSON.parse(window.sessionStorage.getItem('pulse-player-service-status-v2') || 'null');
|
||||||
|
if (cachedStatus && ['online', 'idle', 'offline', 'unknown'].indexOf(cachedStatus.status) !== -1 && typeof cachedStatus.label === 'string') {
|
||||||
|
if (cachedStatus.serviceName === 'Player service') {
|
||||||
|
cachedStatus.serviceName = 'Player';
|
||||||
|
cachedStatus.label = cachedStatus.label.replace(/^Player service online(?= -|$)/, 'Player online');
|
||||||
|
}
|
||||||
|
if (cachedStatus.serviceName === 'Bridge' || cachedStatus.serviceName === 'Player') {
|
||||||
|
playerServiceName = cachedStatus.serviceName;
|
||||||
|
}
|
||||||
|
updateSidebarStatus(cachedStatus.status, cachedStatus.status === 'offline' ? 'No services connected' : cachedStatus.label);
|
||||||
|
hasCachedStatus = true;
|
||||||
|
}
|
||||||
|
} catch (_error) {
|
||||||
|
// Ignore unavailable or malformed cached status.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectDashboardSocket() {
|
function connectDashboardSocket() {
|
||||||
@@ -68,7 +116,9 @@
|
|||||||
function connect() {
|
function connect() {
|
||||||
var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
socket = new WebSocket(protocol + '//' + window.location.host + '/ws/dashboard');
|
socket = new WebSocket(protocol + '//' + window.location.host + '/ws/dashboard');
|
||||||
updateSidebarStatus('unknown', 'Connecting to player feed');
|
if (!hasCachedStatus) {
|
||||||
|
updateSidebarStatus('unknown', buildConnectingLabel());
|
||||||
|
}
|
||||||
|
|
||||||
socket.onmessage = function (event) {
|
socket.onmessage = function (event) {
|
||||||
try {
|
try {
|
||||||
@@ -77,11 +127,14 @@
|
|||||||
if (typeof window.webHandleDashboardState === 'function') {
|
if (typeof window.webHandleDashboardState === 'function') {
|
||||||
window.webHandleDashboardState(payload.state);
|
window.webHandleDashboardState(payload.state);
|
||||||
}
|
}
|
||||||
|
playerServiceName = payload.state && payload.state.playerServiceName === 'Bridge' ? 'Bridge' : 'Player';
|
||||||
var screenCount = Array.isArray(payload.state && payload.state.screens) ? payload.state.screens.length : 0;
|
var screenCount = Array.isArray(payload.state && payload.state.screens) ? payload.state.screens.length : 0;
|
||||||
if (!screenCount) {
|
if (!screenCount) {
|
||||||
updateSidebarStatus('unknown', 'No screens configured');
|
updateSidebarStatus('unknown', 'No screens configured', true);
|
||||||
} else {
|
} else {
|
||||||
updateSidebarStatus(Boolean(payload.state && payload.state.playerServiceConnected), buildLivePlayerFeedLabel(payload.state && payload.state.connectedPlayersCount));
|
var playersConnected = Number(payload.state && payload.state.connectedPlayersCount || 0);
|
||||||
|
var serviceConnected = Boolean(payload.state && payload.state.playerServiceConnected);
|
||||||
|
updateSidebarStatus(serviceConnected ? (playersConnected > 0 ? 'online' : 'idle') : 'offline', buildPlayerServiceLabel(playersConnected, serviceConnected), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
@@ -104,7 +157,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
socket.onopen = function () {
|
socket.onopen = function () {
|
||||||
updateSidebarStatus('unknown', 'Connecting to player feed');
|
if (!hasCachedStatus) {
|
||||||
|
updateSidebarStatus('unknown', buildConnectingLabel());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<link rel="stylesheet" href="/assets/adminlte/bootstrap-icons/css/bootstrap-icons.min.css" />
|
<link rel="stylesheet" href="/assets/adminlte/bootstrap-icons/css/bootstrap-icons.min.css" />
|
||||||
<link rel="stylesheet" href="/assets/adminlte/css/adminlte.min.css" />
|
<link rel="stylesheet" href="/assets/adminlte/css/adminlte.min.css" />
|
||||||
<link rel="stylesheet" href="/assets/adminlte/css/adminlte-colors.min.css" />
|
<link rel="stylesheet" href="/assets/adminlte/css/adminlte-colors.min.css" />
|
||||||
<link rel="stylesheet" href="/assets/css/theme-custom.css?v={{appVersion}}&ui=20261015.6" />
|
<link rel="stylesheet" href="/assets/css/theme-custom.css?v={{appVersion}}&ui=20261025.2" />
|
||||||
<link rel="stylesheet" href="/assets/vendor/animate.css/animate.min.css?v={{appVersion}}" />
|
<link rel="stylesheet" href="/assets/vendor/animate.css/animate.min.css?v={{appVersion}}" />
|
||||||
{{#if stylesheets.length}}
|
{{#if stylesheets.length}}
|
||||||
{{#each stylesheets}}
|
{{#each stylesheets}}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const { createDashboardStateService } = require('../src/web/lib/dashboard-state'
|
|||||||
|
|
||||||
test('dashboard state counts active players from the registry heartbeat', async () => {
|
test('dashboard state counts active players from the registry heartbeat', async () => {
|
||||||
const service = createDashboardStateService({
|
const service = createDashboardStateService({
|
||||||
|
playerServiceName: 'Bridge',
|
||||||
pool: {
|
pool: {
|
||||||
async query(sql) {
|
async query(sql) {
|
||||||
if (String(sql || '').includes('COUNT(*) AS connected_count')) {
|
if (String(sql || '').includes('COUNT(*) AS connected_count')) {
|
||||||
@@ -64,6 +65,7 @@ test('dashboard state counts active players from the registry heartbeat', async
|
|||||||
const state = await service.buildDashboardState();
|
const state = await service.buildDashboardState();
|
||||||
|
|
||||||
assert.equal(state.connectedPlayersCount, 6);
|
assert.equal(state.connectedPlayersCount, 6);
|
||||||
|
assert.equal(state.playerServiceName, 'Bridge');
|
||||||
assert.equal(state.playerServiceConnected, true);
|
assert.equal(state.playerServiceConnected, true);
|
||||||
assert.equal(state.connectedClientsCount, 1);
|
assert.equal(state.connectedClientsCount, 1);
|
||||||
assert.equal(state.clients[0].player_identifier, 'player-alpha');
|
assert.equal(state.clients[0].player_identifier, 'player-alpha');
|
||||||
|
|||||||
+167
-7
@@ -3,13 +3,18 @@ const assert = require('node:assert/strict');
|
|||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
const vm = require('node:vm');
|
const vm = require('node:vm');
|
||||||
|
|
||||||
test('system status shows connected player count in the live feed label', () => {
|
test('system status shows connected player count in the player label', () => {
|
||||||
const script = fs.readFileSync(require.resolve('../src/web/public/js/shared/system-status.js'), 'utf8');
|
const script = fs.readFileSync(require.resolve('../src/web/public/js/shared/system-status.js'), 'utf8');
|
||||||
|
const dotClasses = new Set();
|
||||||
const elements = {
|
const elements = {
|
||||||
'sidebar-status-dot': {
|
'sidebar-status-dot': {
|
||||||
classList: {
|
classList: {
|
||||||
remove() {},
|
remove(...names) {
|
||||||
add() {}
|
names.forEach((name) => dotClasses.delete(name));
|
||||||
|
},
|
||||||
|
add(name) {
|
||||||
|
dotClasses.add(name);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setAttribute() {}
|
setAttribute() {}
|
||||||
},
|
},
|
||||||
@@ -64,22 +69,29 @@ test('system status shows connected player count in the live feed label', () =>
|
|||||||
type: 'dashboard-state',
|
type: 'dashboard-state',
|
||||||
state: {
|
state: {
|
||||||
screens: [{ slug: 'alpha' }],
|
screens: [{ slug: 'alpha' }],
|
||||||
|
playerServiceName: 'Bridge',
|
||||||
playerServiceConnected: true,
|
playerServiceConnected: true,
|
||||||
connectedPlayersCount: 4
|
connectedPlayersCount: 4
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(elements['sidebar-status-text'].textContent, 'Live player feed - 4 players connected');
|
assert.equal(elements['sidebar-status-text'].textContent, 'Bridge online - 4 players connected');
|
||||||
|
assert.equal(dotClasses.has('status-dot--online'), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('system status shows an explicit idle label when no players are connected', () => {
|
test('system status shows an explicit idle label when no players are connected', () => {
|
||||||
const script = fs.readFileSync(require.resolve('../src/web/public/js/shared/system-status.js'), 'utf8');
|
const script = fs.readFileSync(require.resolve('../src/web/public/js/shared/system-status.js'), 'utf8');
|
||||||
|
const dotClasses = new Set();
|
||||||
const elements = {
|
const elements = {
|
||||||
'sidebar-status-dot': {
|
'sidebar-status-dot': {
|
||||||
classList: {
|
classList: {
|
||||||
remove() {},
|
remove(...names) {
|
||||||
add() {}
|
names.forEach((name) => dotClasses.delete(name));
|
||||||
|
},
|
||||||
|
add(name) {
|
||||||
|
dotClasses.add(name);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setAttribute() {}
|
setAttribute() {}
|
||||||
},
|
},
|
||||||
@@ -134,11 +146,159 @@ test('system status shows an explicit idle label when no players are connected',
|
|||||||
type: 'dashboard-state',
|
type: 'dashboard-state',
|
||||||
state: {
|
state: {
|
||||||
screens: [{ slug: 'alpha' }],
|
screens: [{ slug: 'alpha' }],
|
||||||
|
playerServiceName: 'Bridge',
|
||||||
playerServiceConnected: true,
|
playerServiceConnected: true,
|
||||||
connectedPlayersCount: 0
|
connectedPlayersCount: 0
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(elements['sidebar-status-text'].textContent, 'Player feed online - no players connected');
|
assert.equal(elements['sidebar-status-text'].textContent, 'Bridge online - no players connected');
|
||||||
|
assert.equal(dotClasses.has('status-dot--idle'), true);
|
||||||
|
|
||||||
|
sockets[0].onmessage({
|
||||||
|
data: JSON.stringify({
|
||||||
|
type: 'dashboard-state',
|
||||||
|
state: {
|
||||||
|
screens: [{ slug: 'alpha' }],
|
||||||
|
playerServiceName: 'Bridge',
|
||||||
|
playerServiceConnected: false,
|
||||||
|
connectedPlayersCount: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(elements['sidebar-status-text'].textContent, 'No services connected');
|
||||||
|
assert.equal(dotClasses.has('status-dot--offline'), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('system status keeps the last service label while a new page reconnects', () => {
|
||||||
|
const script = fs.readFileSync(require.resolve('../src/web/public/js/shared/system-status.js'), 'utf8');
|
||||||
|
const elements = {
|
||||||
|
'sidebar-status-dot': {
|
||||||
|
classList: {
|
||||||
|
remove() {},
|
||||||
|
add() {}
|
||||||
|
},
|
||||||
|
setAttribute() {}
|
||||||
|
},
|
||||||
|
'sidebar-status-text': {
|
||||||
|
textContent: 'Player service'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const storedValues = {
|
||||||
|
'pulse-player-service-status-v2': JSON.stringify({ status: 'online', label: 'Player service online - 1 player connected', serviceName: 'Player service' })
|
||||||
|
};
|
||||||
|
const sockets = [];
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
document: {
|
||||||
|
getElementById(id) {
|
||||||
|
return elements[id] || null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
WebSocket: true,
|
||||||
|
location: {
|
||||||
|
protocol: 'http:',
|
||||||
|
host: 'example.test'
|
||||||
|
},
|
||||||
|
sessionStorage: {
|
||||||
|
getItem(key) {
|
||||||
|
return storedValues[key] || null;
|
||||||
|
},
|
||||||
|
setItem(key, value) {
|
||||||
|
storedValues[key] = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setTimeout() {
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
clearTimeout() {},
|
||||||
|
webHandleDashboardState() {}
|
||||||
|
},
|
||||||
|
WebSocket: function MockWebSocket(url) {
|
||||||
|
this.url = url;
|
||||||
|
sockets.push(this);
|
||||||
|
this.close = function () {};
|
||||||
|
},
|
||||||
|
JSON: JSON,
|
||||||
|
Number: Number,
|
||||||
|
String: String,
|
||||||
|
Boolean: Boolean,
|
||||||
|
Array: Array,
|
||||||
|
Object: Object,
|
||||||
|
Math: Math,
|
||||||
|
setTimeout() {},
|
||||||
|
clearTimeout() {},
|
||||||
|
console: console
|
||||||
|
};
|
||||||
|
context.window.document = context.document;
|
||||||
|
context.window.WebSocket = context.WebSocket;
|
||||||
|
|
||||||
|
vm.runInNewContext(script, context);
|
||||||
|
|
||||||
|
assert.equal(elements['sidebar-status-text'].textContent, 'Player online - 1 player connected');
|
||||||
|
sockets[0].onopen();
|
||||||
|
assert.equal(elements['sidebar-status-text'].textContent, 'Player online - 1 player connected');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('system status uses the same offline label after restoring a cached bridge status', () => {
|
||||||
|
const script = fs.readFileSync(require.resolve('../src/web/public/js/shared/system-status.js'), 'utf8');
|
||||||
|
const elements = {
|
||||||
|
'sidebar-status-dot': {
|
||||||
|
classList: {
|
||||||
|
remove() {},
|
||||||
|
add() {}
|
||||||
|
},
|
||||||
|
setAttribute() {}
|
||||||
|
},
|
||||||
|
'sidebar-status-text': {
|
||||||
|
textContent: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const context = {
|
||||||
|
document: {
|
||||||
|
getElementById(id) {
|
||||||
|
return elements[id] || null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
WebSocket: true,
|
||||||
|
location: {
|
||||||
|
protocol: 'http:',
|
||||||
|
host: 'example.test'
|
||||||
|
},
|
||||||
|
sessionStorage: {
|
||||||
|
getItem() {
|
||||||
|
return JSON.stringify({ status: 'offline', label: 'Bridge offline', serviceName: 'Bridge' });
|
||||||
|
},
|
||||||
|
setItem() {}
|
||||||
|
},
|
||||||
|
setTimeout() {
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
clearTimeout() {},
|
||||||
|
webHandleDashboardState() {}
|
||||||
|
},
|
||||||
|
WebSocket: function MockWebSocket() {
|
||||||
|
this.close = function () {};
|
||||||
|
},
|
||||||
|
JSON: JSON,
|
||||||
|
Number: Number,
|
||||||
|
String: String,
|
||||||
|
Boolean: Boolean,
|
||||||
|
Array: Array,
|
||||||
|
Object: Object,
|
||||||
|
Math: Math,
|
||||||
|
setTimeout() {},
|
||||||
|
clearTimeout() {},
|
||||||
|
console: console
|
||||||
|
};
|
||||||
|
context.window.document = context.document;
|
||||||
|
context.window.WebSocket = context.WebSocket;
|
||||||
|
|
||||||
|
vm.runInNewContext(script, context);
|
||||||
|
|
||||||
|
assert.equal(elements['sidebar-status-text'].textContent, 'No services connected');
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user