Skip to content

Commit 291b16b

Browse files
committed
fix(testing): improve test mode ownership handling and add takeover warnings
1 parent c0c7018 commit 291b16b

1 file changed

Lines changed: 141 additions & 5 deletions

File tree

www/testing.php

Lines changed: 141 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,104 @@ function PrintSequenceOptions()
9494

9595
</head>
9696

97-
<body onunload='DisableTestMode();DisableDMXTestMode();'>
97+
<body onunload='HandlePageUnload();'>
9898

9999
<script type="text/javascript">
100100
if (!window.console) console = { log: function () { } };
101101

102102
var modelInfos = [];
103103
var lastEnabledState = 0;
104104

105+
// fppd runs one test at a time, but the Channel Testing and Channel Fader
106+
// tabs each have their own Enable Test Mode checkbox. Remember which tab
107+
// started the running test so switching tabs shows the truth rather than an
108+
// unticked box sitting next to output that is still running. sessionStorage
109+
// carries the owner across navigating away from and back to this page.
110+
var TEST_OWNER_KEY = 'fppTestOwner';
111+
var testOwner = null;
112+
var pageUnloading = false;
113+
114+
function StoreTestOwner(owner) {
115+
// The Test Stop we fire on unload usually doesn't make it out before the
116+
// page goes away, so keep the stored owner rather than clearing it - the
117+
// test is most likely still running when we come back.
118+
if (pageUnloading && !owner) {
119+
return;
120+
}
121+
testOwner = owner;
122+
try {
123+
if (owner) {
124+
sessionStorage.setItem(TEST_OWNER_KEY, owner);
125+
} else {
126+
sessionStorage.removeItem(TEST_OWNER_KEY);
127+
}
128+
} catch (e) {
129+
// sessionStorage blocked; the in-memory owner still covers this page view
130+
}
131+
}
132+
133+
function LoadTestOwner() {
134+
try {
135+
return sessionStorage.getItem(TEST_OWNER_KEY);
136+
} catch (e) {
137+
return null;
138+
}
139+
}
140+
141+
// Each tab warns when the other tab owns the running test, since enabling
142+
// test mode here replaces it.
143+
function UpdateTakeoverNotices() {
144+
$('#channelTestTakeover').toggleClass('d-none', testOwner != 'dmx');
145+
$('#dmxTestTakeover').toggleClass('d-none', testOwner != 'channels');
146+
}
147+
148+
// Point both tabs' checkboxes at the one test fppd is actually running.
149+
// 'enabled' is fppd's real state, from api/testmode.
150+
function ApplyTestOwnership(enabled) {
151+
var owner = null;
152+
if (enabled) {
153+
// A test we never started (another browser, or a page load with no
154+
// stored owner) is attributed to the Channel Testing tab, whose
155+
// controls GetTestMode() fills in from the running test.
156+
owner = testOwner || LoadTestOwner() || 'channels';
157+
}
158+
StoreTestOwner(owner);
159+
160+
lastEnabledState = (owner == 'channels') ? 1 : 0;
161+
dmxLastEnabled = (owner == 'dmx') ? 1 : 0;
162+
$('#testModeEnabled').prop('checked', owner == 'channels');
163+
$('#dmxTestEnabled').prop('checked', owner == 'dmx');
164+
if (owner != 'dmx') {
165+
DMXSineStop();
166+
}
167+
UpdateTakeoverNotices();
168+
}
169+
170+
// Re-read fppd's test state when switching between the top-level tabs.
171+
function RefreshTestState() {
172+
$.ajax({
173+
url: "api/testmode",
174+
dataType: 'json',
175+
success: function (data) {
176+
ApplyTestOwnership(data.enabled ? true : false);
177+
}
178+
});
179+
}
180+
181+
function StopRunningTest() {
182+
var data = {
183+
"command": "Test Stop",
184+
"multisyncCommand": $('#multisyncEnabled').is(':checked') || $('#dmxMultisyncEnabled').is(':checked'),
185+
"multisyncHosts": "",
186+
"args": []
187+
};
188+
$.post("api/command", JSON.stringify(data)).done(function () {
189+
ApplyTestOwnership(false);
190+
}).fail(function () {
191+
DialogError("Failed to stop Test Mode", "Stop failed");
192+
});
193+
}
194+
105195
function StringsChanged() {
106196
var id = parseInt($('#modelName').val());
107197

@@ -256,8 +346,7 @@ function GetTestMode() {
256346
dataType: 'json',
257347
success: function (data) {
258348
if (data.enabled) {
259-
$('#testModeEnabled').prop('checked', true);
260-
lastEnabledState = 1;
349+
ApplyTestOwnership(true);
261350

262351
if (data.hasOwnProperty('cycleMS')) {
263352
$("#testModeCycleMSText").html(data.cycleMS);
@@ -299,11 +388,11 @@ function GetTestMode() {
299388
}
300389
}
301390
else {
302-
$('#testModeEnabled').prop('checked', false);
391+
ApplyTestOwnership(false);
303392
}
304393
},
305394
failure: function (data) {
306-
$('#testModeEnabled').prop('checked', false);
395+
ApplyTestOwnership(false);
307396
}
308397
});
309398
}
@@ -551,6 +640,24 @@ function SetTestMode() {
551640
}
552641

553642
lastEnabledState = enabled;
643+
644+
if (enabled) {
645+
// This tab now owns the one fppd test, replacing anything the Channel
646+
// Fader tab had running.
647+
StoreTestOwner('channels');
648+
$('#dmxTestEnabled').prop('checked', false);
649+
dmxLastEnabled = 0;
650+
DMXSineStop();
651+
} else if (testOwner == 'channels') {
652+
StoreTestOwner(null);
653+
}
654+
UpdateTakeoverNotices();
655+
}
656+
657+
function HandlePageUnload() {
658+
pageUnloading = true;
659+
DisableTestMode();
660+
DisableDMXTestMode();
554661
}
555662

556663
function DisableTestMode() {
@@ -1082,6 +1189,13 @@ function SetDMXTestMode() {
10821189
});
10831190

10841191
dmxLastEnabled = enabled;
1192+
1193+
if (enabled && count > 0) {
1194+
StoreTestOwner('dmx');
1195+
} else if (testOwner == 'dmx') {
1196+
StoreTestOwner(null);
1197+
}
1198+
UpdateTakeoverNotices();
10851199
}
10861200

10871201
function DisableDMXTestMode() {
@@ -1268,6 +1382,12 @@ function DisableDMXTestMode() {
12681382
})
12691383
.css('background-color', '#ff00ff');
12701384

1385+
// Switching tabs doesn't stop the running test, so re-read its state to
1386+
// keep the checkbox on the newly shown tab honest.
1387+
$('#tab-channels-tab, #tab-dmx-tab, #tab-sequence-tab').on('shown.bs.tab', function () {
1388+
RefreshTestState();
1389+
});
1390+
12711391
UpdateWhiteSliderState();
12721392
GetTestMode();
12731393
RebuildDMXSliders();
@@ -1447,6 +1567,14 @@ function DisableDMXTestMode() {
14471567
aria-labelledby="interface-settings-tab">
14481568

14491569

1570+
<div id='channelTestTakeover' class="alert alert-warning d-none d-flex flex-wrap align-items-center gap-2"
1571+
role="alert">
1572+
<i class="fas fa-exclamation-triangle"></i>
1573+
<span>A test started on the <b>Channel Fader</b> tab is still running. Enabling
1574+
test mode here will take it over.</span>
1575+
<button type="button" class="btn btn-sm btn-outline-secondary ms-auto"
1576+
onclick="StopRunningTest();">Stop Test</button>
1577+
</div>
14501578
<!-- Page-Wide Settings -->
14511579
<div class="backdrop-dark mb-3">
14521580
<div class="row">
@@ -2000,6 +2128,14 @@ class="custom-control-label"><b>Fill</b></label>
20002128
</div>
20012129
</div>
20022130
<div id='tab-dmx' class="tab-pane fade" role="tabpanel" aria-labelledby="tab-dmx-tab">
2131+
<div id='dmxTestTakeover' class="alert alert-warning d-none d-flex flex-wrap align-items-center gap-2"
2132+
role="alert">
2133+
<i class="fas fa-exclamation-triangle"></i>
2134+
<span>A test started on the <b>Channel Testing</b> tab is still running. Enabling
2135+
test mode here will take it over.</span>
2136+
<button type="button" class="btn btn-sm btn-outline-secondary ms-auto"
2137+
onclick="StopRunningTest();">Stop Test</button>
2138+
</div>
20032139
<div class="row">
20042140
<div class="col-md-3">
20052141
<div class="backdrop-dark">

0 commit comments

Comments
 (0)