Add player control-plane and dashboard updates
This commit is contained in:
@@ -355,3 +355,397 @@ test('screen controls include an all screens option and update the target summar
|
||||
assert.equal(commandInput.value, 'pause');
|
||||
assert.equal(pausedInput.value, 'false');
|
||||
});
|
||||
|
||||
test('dashboard client refresh respects the active search filter', () => {
|
||||
const script = fs.readFileSync(require.resolve('../src/web/public/js/dashboard/dashboard-page.js'), 'utf8');
|
||||
const tbody = {
|
||||
innerHTML: '<tr><td>stale</td></tr>',
|
||||
addEventListener() {}
|
||||
};
|
||||
const table = {
|
||||
getAttribute(name) {
|
||||
if (name === 'data-has-actions-column') {
|
||||
return 'false';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
};
|
||||
const context = {
|
||||
document: {
|
||||
body: {
|
||||
classList: {
|
||||
toggle() {},
|
||||
add() {},
|
||||
remove() {}
|
||||
}
|
||||
},
|
||||
getElementById(id) {
|
||||
if (id === 'dashboard-clients-table') {
|
||||
return table;
|
||||
}
|
||||
if (id === 'dashboard-clients-table-body') {
|
||||
return tbody;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
querySelector() {
|
||||
return null;
|
||||
},
|
||||
querySelectorAll() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
window: {
|
||||
location: {
|
||||
search: '?search=beta',
|
||||
protocol: 'http:',
|
||||
host: 'example.test'
|
||||
},
|
||||
webUiHelpers: {
|
||||
escapeHtml(value) { return String(value); },
|
||||
formatDashboardDate(value) { return String(value); },
|
||||
getClientRowKey(client) { return String(client && client.id || ''); },
|
||||
getClientDisplayName(client) { return String(client && (client.client_name || client.name || client.clientId) || ''); },
|
||||
setButtonVariant() {},
|
||||
normalizeDisplayIp(value) { return String(value); }
|
||||
},
|
||||
WebSocket: null,
|
||||
setTimeout() { return 1; },
|
||||
clearTimeout() {},
|
||||
alert() {},
|
||||
prompt() {
|
||||
return null;
|
||||
},
|
||||
webHandleDashboardState() {}
|
||||
},
|
||||
WebSocket: function MockWebSocket() {},
|
||||
JSON: JSON,
|
||||
Number: Number,
|
||||
String: String,
|
||||
Boolean: Boolean,
|
||||
Array: Array,
|
||||
Object: Object,
|
||||
Math: Math,
|
||||
Set: Set,
|
||||
URLSearchParams: URLSearchParams,
|
||||
FormData: function FormData() {},
|
||||
setTimeout() {},
|
||||
clearTimeout() {},
|
||||
console: console
|
||||
};
|
||||
context.window.document = context.document;
|
||||
context.window.WebSocket = context.WebSocket;
|
||||
|
||||
vm.runInNewContext(script, context);
|
||||
|
||||
context.window.webHandleDashboardState({
|
||||
clients: [
|
||||
{ id: 'alpha', client_name: 'Alpha', clientId: 'alpha', screen_slug: 'alpha', clientIp: '10.0.0.1' },
|
||||
{ id: 'beta', client_name: 'Beta', clientId: 'beta', screen_slug: 'beta', clientIp: '10.0.0.2' }
|
||||
]
|
||||
});
|
||||
|
||||
assert.match(tbody.innerHTML, /Beta/);
|
||||
assert.doesNotMatch(tbody.innerHTML, /Alpha/);
|
||||
});
|
||||
|
||||
test('dashboard client refresh respects the live search input before the URL updates', () => {
|
||||
const script = fs.readFileSync(require.resolve('../src/web/public/js/dashboard/dashboard-page.js'), 'utf8');
|
||||
const searchInput = {
|
||||
value: 'beta'
|
||||
};
|
||||
const tbody = {
|
||||
innerHTML: '<tr><td>stale</td></tr>',
|
||||
addEventListener() {}
|
||||
};
|
||||
const table = {
|
||||
getAttribute(name) {
|
||||
if (name === 'data-has-actions-column') {
|
||||
return 'false';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
};
|
||||
const context = {
|
||||
document: {
|
||||
body: {
|
||||
classList: {
|
||||
toggle() {},
|
||||
add() {},
|
||||
remove() {}
|
||||
}
|
||||
},
|
||||
getElementById(id) {
|
||||
if (id === 'dashboard-clients-table') {
|
||||
return table;
|
||||
}
|
||||
if (id === 'dashboard-clients-table-body') {
|
||||
return tbody;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
querySelector(selector) {
|
||||
if (selector === '[data-table-search]') {
|
||||
return searchInput;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
querySelectorAll() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
window: {
|
||||
location: {
|
||||
search: '',
|
||||
protocol: 'http:',
|
||||
host: 'example.test'
|
||||
},
|
||||
webUiHelpers: {
|
||||
escapeHtml(value) { return String(value); },
|
||||
formatDashboardDate(value) { return String(value); },
|
||||
getClientRowKey(client) { return String(client && client.id || ''); },
|
||||
getClientDisplayName(client) { return String(client && (client.client_name || client.name || client.clientId) || ''); },
|
||||
setButtonVariant() {},
|
||||
normalizeDisplayIp(value) { return String(value); }
|
||||
},
|
||||
WebSocket: null,
|
||||
setTimeout() { return 1; },
|
||||
clearTimeout() {},
|
||||
alert() {},
|
||||
prompt() {
|
||||
return null;
|
||||
},
|
||||
webHandleDashboardState() {}
|
||||
},
|
||||
WebSocket: function MockWebSocket() {},
|
||||
JSON: JSON,
|
||||
Number: Number,
|
||||
String: String,
|
||||
Boolean: Boolean,
|
||||
Array: Array,
|
||||
Object: Object,
|
||||
Math: Math,
|
||||
Set: Set,
|
||||
URLSearchParams: URLSearchParams,
|
||||
FormData: function FormData() {},
|
||||
setTimeout() {},
|
||||
clearTimeout() {},
|
||||
console: console
|
||||
};
|
||||
context.window.document = context.document;
|
||||
context.window.WebSocket = context.WebSocket;
|
||||
|
||||
vm.runInNewContext(script, context);
|
||||
|
||||
context.window.webHandleDashboardState({
|
||||
clients: [
|
||||
{ id: 'alpha', client_name: 'Alpha', clientId: 'alpha', screen_slug: 'alpha', clientIp: '10.0.0.1' },
|
||||
{ id: 'beta', client_name: 'Beta', clientId: 'beta', screen_slug: 'beta', clientIp: '10.0.0.2' }
|
||||
]
|
||||
});
|
||||
|
||||
assert.match(tbody.innerHTML, /Beta/);
|
||||
assert.doesNotMatch(tbody.innerHTML, /Alpha/);
|
||||
});
|
||||
|
||||
test('dashboard client refresh does not rerender while a table search is loading', () => {
|
||||
const script = fs.readFileSync(require.resolve('../src/web/public/js/dashboard/dashboard-page.js'), 'utf8');
|
||||
const tbody = {
|
||||
innerHTML: '<tr><td>stale</td></tr>',
|
||||
addEventListener() {}
|
||||
};
|
||||
const table = {
|
||||
getAttribute(name) {
|
||||
if (name === 'data-has-actions-column') {
|
||||
return 'false';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
};
|
||||
const loadingMarker = {};
|
||||
const context = {
|
||||
document: {
|
||||
body: {
|
||||
classList: {
|
||||
toggle() {},
|
||||
add() {},
|
||||
remove() {}
|
||||
}
|
||||
},
|
||||
getElementById(id) {
|
||||
if (id === 'dashboard-clients-table') {
|
||||
return table;
|
||||
}
|
||||
if (id === 'dashboard-clients-table-body') {
|
||||
return tbody;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
querySelector(selector) {
|
||||
if (selector === '[data-table-search-loading="true"]') {
|
||||
return loadingMarker;
|
||||
}
|
||||
if (selector === '[data-table-search]') {
|
||||
return { value: 'beta' };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
querySelectorAll() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
window: {
|
||||
location: {
|
||||
search: '?search=beta',
|
||||
protocol: 'http:',
|
||||
host: 'example.test'
|
||||
},
|
||||
webUiHelpers: {
|
||||
escapeHtml(value) { return String(value); },
|
||||
formatDashboardDate(value) { return String(value); },
|
||||
getClientRowKey(client) { return String(client && client.id || ''); },
|
||||
getClientDisplayName(client) { return String(client && (client.client_name || client.name || client.clientId) || ''); },
|
||||
setButtonVariant() {},
|
||||
normalizeDisplayIp(value) { return String(value); }
|
||||
},
|
||||
WebSocket: null,
|
||||
setTimeout() { return 1; },
|
||||
clearTimeout() {},
|
||||
alert() {},
|
||||
prompt() {
|
||||
return null;
|
||||
},
|
||||
webHandleDashboardState() {}
|
||||
},
|
||||
WebSocket: function MockWebSocket() {},
|
||||
JSON: JSON,
|
||||
Number: Number,
|
||||
String: String,
|
||||
Boolean: Boolean,
|
||||
Array: Array,
|
||||
Object: Object,
|
||||
Math: Math,
|
||||
Set: Set,
|
||||
URLSearchParams: URLSearchParams,
|
||||
FormData: function FormData() {},
|
||||
setTimeout() {},
|
||||
clearTimeout() {},
|
||||
console: console
|
||||
};
|
||||
context.window.document = context.document;
|
||||
context.window.WebSocket = context.WebSocket;
|
||||
|
||||
vm.runInNewContext(script, context);
|
||||
|
||||
context.window.webHandleDashboardState({
|
||||
clients: [
|
||||
{ id: 'alpha', client_name: 'Alpha', clientId: 'alpha', screen_slug: 'alpha', clientIp: '10.0.0.1' },
|
||||
{ id: 'beta', client_name: 'Beta', clientId: 'beta', screen_slug: 'beta', clientIp: '10.0.0.2' }
|
||||
]
|
||||
});
|
||||
|
||||
assert.equal(tbody.innerHTML, '<tr><td>stale</td></tr>');
|
||||
});
|
||||
|
||||
test('dashboard client table can rehydrate actions after a search swap', () => {
|
||||
const script = fs.readFileSync(require.resolve('../src/web/public/js/dashboard/dashboard-page.js'), 'utf8');
|
||||
const tbody = {
|
||||
innerHTML: '<tr><td>stale</td></tr>',
|
||||
addEventListener() {}
|
||||
};
|
||||
const table = {
|
||||
getAttribute(name) {
|
||||
if (name === 'data-has-actions-column') {
|
||||
return 'true';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
};
|
||||
const context = {
|
||||
document: {
|
||||
body: {
|
||||
classList: {
|
||||
toggle() {},
|
||||
add() {},
|
||||
remove() {}
|
||||
}
|
||||
},
|
||||
getElementById(id) {
|
||||
if (id === 'dashboard-clients-table') {
|
||||
return table;
|
||||
}
|
||||
if (id === 'dashboard-clients-table-body') {
|
||||
return tbody;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
querySelector(selector) {
|
||||
if (selector === '[data-table-search]') {
|
||||
return { value: '48' };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
querySelectorAll() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
window: {
|
||||
location: {
|
||||
search: '?search=48',
|
||||
protocol: 'http:',
|
||||
host: 'example.test'
|
||||
},
|
||||
webUiHelpers: {
|
||||
escapeHtml(value) { return String(value); },
|
||||
formatDashboardDate(value) { return String(value); },
|
||||
getClientRowKey(client) { return String(client && client.id || ''); },
|
||||
getClientDisplayName(client) { return String(client && (client.client_name || client.name || client.clientId) || ''); },
|
||||
setButtonVariant() {},
|
||||
normalizeDisplayIp(value) { return String(value); }
|
||||
},
|
||||
WebSocket: null,
|
||||
setTimeout() { return 1; },
|
||||
clearTimeout() {},
|
||||
requestAnimationFrame(callback) {
|
||||
callback();
|
||||
},
|
||||
alert() {},
|
||||
prompt() {
|
||||
return null;
|
||||
},
|
||||
webHandleDashboardState() {}
|
||||
},
|
||||
WebSocket: function MockWebSocket() {},
|
||||
JSON: JSON,
|
||||
Number: Number,
|
||||
String: String,
|
||||
Boolean: Boolean,
|
||||
Array: Array,
|
||||
Object: Object,
|
||||
Math: Math,
|
||||
Set: Set,
|
||||
URLSearchParams: URLSearchParams,
|
||||
FormData: function FormData() {},
|
||||
setTimeout() {},
|
||||
clearTimeout() {},
|
||||
console: console
|
||||
};
|
||||
context.window.document = context.document;
|
||||
context.window.WebSocket = context.WebSocket;
|
||||
|
||||
vm.runInNewContext(script, context);
|
||||
|
||||
context.window.webHandleDashboardState({
|
||||
clients: [
|
||||
{ id: '48f94e8d-a307-45f8-99a5-dafd3f0e2282', client_name: 'Beta', clientId: '48f94e8d-a307-45f8-99a5-dafd3f0e2282', screen_slug: 'beta', clientIp: '10.0.0.2' },
|
||||
{ id: 'alpha', client_name: 'Alpha', clientId: 'alpha', screen_slug: 'alpha', clientIp: '10.0.0.1' }
|
||||
]
|
||||
});
|
||||
|
||||
tbody.innerHTML = '<tr data-client-key="48f94e8d-a307-45f8-99a5-dafd3f0e2282"><td data-label="Client"><div>Beta</div></td></tr>';
|
||||
context.window.webRefreshClientTableFromLatestState();
|
||||
|
||||
assert.match(tbody.innerHTML, /data-label="Actions"/);
|
||||
assert.match(tbody.innerHTML, /Pause/);
|
||||
assert.match(tbody.innerHTML, /Blackout/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user