Skip to content

Commit 5299661

Browse files
committed
Update footer and some visuals
1 parent 95aaa2e commit 5299661

File tree

9 files changed

+270
-13
lines changed

9 files changed

+270
-13
lines changed

src/PerfProblemSimulator/Controllers/ConfigController.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public ActionResult<ClientConfig> GetConfig()
3333
{
3434
return Ok(new ClientConfig
3535
{
36-
AppTitle = _options.AppTitle
36+
AppTitle = _options.AppTitle,
37+
PageFooter = _options.PageFooter
3738
});
3839
}
3940
}
@@ -47,4 +48,9 @@ public class ClientConfig
4748
/// The title displayed in the dashboard header.
4849
/// </summary>
4950
public required string AppTitle { get; init; }
51+
52+
/// <summary>
53+
/// Custom HTML content for the page footer. Empty string if not configured.
54+
/// </summary>
55+
public string PageFooter { get; init; } = "";
5056
}

src/PerfProblemSimulator/Controllers/CpuController.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,22 @@ namespace PerfProblemSimulator.Controllers;
3737
public class CpuController : ControllerBase
3838
{
3939
private readonly ICpuStressService _cpuStressService;
40+
private readonly ISimulationTracker _simulationTracker;
4041
private readonly ILogger<CpuController> _logger;
4142

4243
/// <summary>
4344
/// Initializes a new instance of the <see cref="CpuController"/> class.
4445
/// </summary>
4546
/// <param name="cpuStressService">Service for triggering CPU stress.</param>
47+
/// <param name="simulationTracker">Service for tracking and cancelling simulations.</param>
4648
/// <param name="logger">Logger for request tracking.</param>
4749
public CpuController(
4850
ICpuStressService cpuStressService,
51+
ISimulationTracker simulationTracker,
4952
ILogger<CpuController> logger)
5053
{
5154
_cpuStressService = cpuStressService ?? throw new ArgumentNullException(nameof(cpuStressService));
55+
_simulationTracker = simulationTracker ?? throw new ArgumentNullException(nameof(simulationTracker));
5256
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
5357
}
5458

@@ -137,4 +141,26 @@ public async Task<IActionResult> TriggerHighCpu(
137141
ErrorResponse.SimulationError("Failed to start CPU stress simulation. See server logs for details."));
138142
}
139143
}
144+
145+
/// <summary>
146+
/// Stops all active CPU stress simulations.
147+
/// </summary>
148+
/// <returns>Number of simulations that were stopped.</returns>
149+
/// <response code="200">CPU stress simulations stopped.</response>
150+
[HttpPost("stop")]
151+
[ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
152+
public IActionResult Stop()
153+
{
154+
_logger.LogInformation("Stopping all CPU stress simulations");
155+
156+
var cancelled = _simulationTracker.CancelByType(SimulationType.Cpu);
157+
158+
_logger.LogInformation("Stopped {Count} CPU stress simulations", cancelled);
159+
160+
return Ok(new
161+
{
162+
message = $"Stopped {cancelled} CPU stress simulation(s)",
163+
cancelledCount = cancelled
164+
});
165+
}
140166
}

src/PerfProblemSimulator/Models/ProblemSimulatorOptions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,15 @@ public class ProblemSimulatorOptions
2828
/// the environment variable: ProblemSimulator__AppTitle
2929
/// </remarks>
3030
public string AppTitle { get; set; } = "Performance Problem Simulator";
31+
32+
/// <summary>
33+
/// Custom HTML content for the page footer's second line.
34+
/// </summary>
35+
/// <remarks>
36+
/// Can be overridden via Azure App Service configuration using
37+
/// the environment variable: ProblemSimulator__PageFooter
38+
/// Supports HTML content including links.
39+
/// If not set, the footer will only show the app description and build info.
40+
/// </remarks>
41+
public string PageFooter { get; set; } = "";
3142
}

src/PerfProblemSimulator/Services/SimulationTracker.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ void RegisterSimulation(
6262
/// <returns>Number of simulations that were cancelled.</returns>
6363
int CancelAll();
6464

65+
/// <summary>
66+
/// Cancels all active simulations of a specific type.
67+
/// </summary>
68+
/// <param name="type">The simulation type to cancel.</param>
69+
/// <returns>Number of simulations that were cancelled.</returns>
70+
int CancelByType(SimulationType type);
71+
6572
/// <summary>
6673
/// Tries to get information about a specific simulation.
6774
/// </summary>
@@ -272,6 +279,41 @@ public int CancelAll()
272279
return cancelled;
273280
}
274281

282+
/// <inheritdoc />
283+
public int CancelByType(SimulationType type)
284+
{
285+
var cancelled = 0;
286+
var toRemove = new List<Guid>();
287+
288+
foreach (var kvp in _simulations)
289+
{
290+
if (kvp.Value.Info.Type == type)
291+
{
292+
try
293+
{
294+
kvp.Value.CancellationSource.Cancel();
295+
cancelled++;
296+
toRemove.Add(kvp.Key);
297+
}
298+
catch (ObjectDisposedException)
299+
{
300+
// Cancellation source was already disposed, still remove
301+
toRemove.Add(kvp.Key);
302+
}
303+
}
304+
}
305+
306+
// Remove cancelled simulations
307+
foreach (var id in toRemove)
308+
{
309+
_simulations.TryRemove(id, out _);
310+
}
311+
312+
_logger.LogInformation("Cancelled {Count} {Type} simulations", cancelled, type);
313+
314+
return cancelled;
315+
}
316+
275317
/// <inheritdoc />
276318
public bool TryGetSimulation(Guid simulationId, out ActiveSimulationInfo? info)
277319
{

src/PerfProblemSimulator/wwwroot/azure-deployment.html

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,57 @@ <h3>Verify Deployment</h3>
638638
</ol>
639639
</section>
640640

641+
<section id="optional-config" class="card">
642+
<h2>Optional Configuration</h2>
643+
<p>You can customize the application behavior using Azure App Service environment variables.</p>
644+
645+
<h3>Custom Page Footer</h3>
646+
<p>Set a custom footer message that appears on all pages. The footer supports HTML, allowing you to include links.</p>
647+
648+
<h4>Environment Variable</h4>
649+
<table style="width:100%; border-collapse: collapse; margin: 1rem 0;">
650+
<tr style="background: #f5f5f5;">
651+
<th style="padding: 0.75rem; text-align: left; border: 1px solid #ddd;">Variable Name</th>
652+
<th style="padding: 0.75rem; text-align: left; border: 1px solid #ddd;">Description</th>
653+
</tr>
654+
<tr>
655+
<td style="padding: 0.75rem; border: 1px solid #ddd;"><code>ProblemSimulator__PageFooter</code></td>
656+
<td style="padding: 0.75rem; border: 1px solid #ddd;">HTML content for the footer's second line. If not set, only the app description and build info are shown.</td>
657+
</tr>
658+
</table>
659+
660+
<h4>Example Value</h4>
661+
<pre><code>Created by &lt;a href="https://speckit.org/"&gt;SpecKit&lt;/a&gt; and &lt;a href="https://github.com/copilot"&gt;Github Copilot&lt;/a&gt; in collaboration with &lt;a href="mailto:rhamlett@microsoft.com"&gt;Richard Hamlett&lt;/a&gt;</code></pre>
662+
663+
<h4>Setting via Azure CLI</h4>
664+
<pre><code># Set the footer via Azure CLI
665+
az webapp config appsettings set --name $APP_NAME --resource-group $RESOURCE_GROUP \
666+
--settings 'ProblemSimulator__PageFooter=Created by &lt;a href="https://speckit.org/"&gt;SpecKit&lt;/a&gt; and &lt;a href="https://github.com/copilot"&gt;Github Copilot&lt;/a&gt; in collaboration with &lt;a href="mailto:rhamlett@microsoft.com"&gt;Richard Hamlett&lt;/a&gt;'</code></pre>
667+
668+
<h4>Setting via Azure Portal</h4>
669+
<ol>
670+
<li>Navigate to your App Service in the Azure Portal</li>
671+
<li>Go to <strong>Settings</strong><strong>Environment variables</strong></li>
672+
<li>Click <strong>+ Add</strong></li>
673+
<li>Set Name: <code>ProblemSimulator__PageFooter</code></li>
674+
<li>Set Value: Your HTML footer content</li>
675+
<li>Click <strong>Apply</strong>, then <strong>Confirm</strong></li>
676+
</ol>
677+
678+
<h3>Custom App Title</h3>
679+
<p>You can also customize the application title displayed in the header:</p>
680+
<table style="width:100%; border-collapse: collapse; margin: 1rem 0;">
681+
<tr style="background: #f5f5f5;">
682+
<th style="padding: 0.75rem; text-align: left; border: 1px solid #ddd;">Variable Name</th>
683+
<th style="padding: 0.75rem; text-align: left; border: 1px solid #ddd;">Default Value</th>
684+
</tr>
685+
<tr>
686+
<td style="padding: 0.75rem; border: 1px solid #ddd;"><code>ProblemSimulator__AppTitle</code></td>
687+
<td style="padding: 0.75rem; border: 1px solid #ddd;">Performance Problem Simulator</td>
688+
</tr>
689+
</table>
690+
</section>
691+
641692
<section id="troubleshooting" class="card">
642693
<h2>Troubleshooting</h2>
643694

@@ -747,6 +798,9 @@ <h2>Quick Reference - CLI One-Liner</h2>
747798
<li class="doc-toc-item">
748799
<a href="#deploy"><span class="toc-icon">6️⃣</span>Deploy</a>
749800
</li>
801+
<li class="doc-toc-item">
802+
<a href="#optional-config"><span class="toc-icon">⚙️</span>Optional Config</a>
803+
</li>
750804
<div class="doc-toc-divider"></div>
751805
<div class="doc-toc-section-label">Reference</div>
752806
<li class="doc-toc-item">
@@ -759,10 +813,32 @@ <h2>Quick Reference - CLI One-Liner</h2>
759813
</div><!-- /.doc-layout -->
760814

761815
<footer class="footer">
762-
<p>Performance Problem Simulator - Educational Tool for Azure App Service Diagnostics</p>
763-
<p>Created by <a href="https://speckit.org/" target="_blank">SpecKit</a> in collaboration with <a href="mailto:rhamlett@microsoft.com">Richard Hamlett</a></p>
816+
<p>Performance Problem Simulator Educational Tool for Azure App Service Diagnostics</p>
817+
<p id="pageFooterContent"></p>
764818
</footer>
765819

820+
<script>
821+
// Fetch and display custom page footer
822+
(async function() {
823+
try {
824+
const response = await fetch('/api/config');
825+
if (response.ok) {
826+
const config = await response.json();
827+
const footerEl = document.getElementById('pageFooterContent');
828+
if (footerEl) {
829+
if (config.pageFooter && config.pageFooter.trim()) {
830+
footerEl.innerHTML = config.pageFooter;
831+
} else {
832+
footerEl.style.display = 'none';
833+
}
834+
}
835+
}
836+
} catch (e) {
837+
console.error('Failed to fetch config', e);
838+
}
839+
})();
840+
</script>
841+
766842
<script>
767843
// Sidebar drawer toggle
768844
const hamburgerBtn = document.getElementById('hamburger-btn');

src/PerfProblemSimulator/wwwroot/azure-monitoring-guide.html

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,8 +1291,8 @@ <h2>🔗 Additional Resources</h2>
12911291

12921292
<!-- Footer -->
12931293
<footer class="footer">
1294-
<p>Performance Problem Simulator - Educational Tool for Azure App Service Diagnostics</p>
1295-
<p>Created by <a href="https://speckit.org/" target="_blank">SpecKit</a> in collaboration with <a href="mailto:rhamlett@microsoft.com">Richard Hamlett</a></p>
1294+
<p>Performance Problem Simulator Educational Tool for Azure App Service Diagnostics</p>
1295+
<p id="pageFooterContent"></p>
12961296
</footer>
12971297
</div><!-- /.doc-container -->
12981298
</div><!-- /.doc-main -->
@@ -1348,6 +1348,28 @@ <h2>🔗 Additional Resources</h2>
13481348
</aside>
13491349
</div><!-- /.doc-layout -->
13501350

1351+
<script>
1352+
// Fetch and display custom page footer
1353+
(async function() {
1354+
try {
1355+
const response = await fetch('/api/config');
1356+
if (response.ok) {
1357+
const config = await response.json();
1358+
const footerEl = document.getElementById('pageFooterContent');
1359+
if (footerEl) {
1360+
if (config.pageFooter && config.pageFooter.trim()) {
1361+
footerEl.innerHTML = config.pageFooter;
1362+
} else {
1363+
footerEl.style.display = 'none';
1364+
}
1365+
}
1366+
}
1367+
} catch (e) {
1368+
console.error('Failed to fetch config', e);
1369+
}
1370+
})();
1371+
</script>
1372+
13511373
<script>
13521374
// Sidebar drawer toggle
13531375
const hamburgerBtn = document.getElementById('hamburger-btn');

src/PerfProblemSimulator/wwwroot/documentation.html

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,8 +1234,8 @@ <h3>What It Tests</h3>
12341234

12351235
<!-- Footer -->
12361236
<footer class="footer">
1237-
<p>Performance Problem Simulator - Educational Tool for Azure App Service Diagnostics</p>
1238-
<p>Created by <a href="https://speckit.org/" target="_blank">SpecKit</a> in collaboration with <a href="mailto:rhamlett@microsoft.com">Richard Hamlett</a></p>
1237+
<p>Performance Problem Simulator Educational Tool for Azure App Service Diagnostics</p>
1238+
<p id="pageFooterContent"></p>
12391239
</footer>
12401240
</div><!-- /.doc-container -->
12411241
</div><!-- /.doc-main -->
@@ -1289,6 +1289,28 @@ <h3>What It Tests</h3>
12891289
</aside>
12901290
</div><!-- /.doc-layout -->
12911291

1292+
<script>
1293+
// Fetch and display custom page footer
1294+
(async function() {
1295+
try {
1296+
const response = await fetch('/api/config');
1297+
if (response.ok) {
1298+
const config = await response.json();
1299+
const footerEl = document.getElementById('pageFooterContent');
1300+
if (footerEl) {
1301+
if (config.pageFooter && config.pageFooter.trim()) {
1302+
footerEl.innerHTML = config.pageFooter;
1303+
} else {
1304+
footerEl.style.display = 'none';
1305+
}
1306+
}
1307+
}
1308+
} catch (e) {
1309+
console.error('Failed to fetch config', e);
1310+
}
1311+
})();
1312+
</script>
1313+
12921314
<script>
12931315
// Sidebar drawer toggle
12941316
const hamburgerBtn = document.getElementById('hamburger-btn');

src/PerfProblemSimulator/wwwroot/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ <h2>🔥 PerfSim .NET</h2>
6868
</a>
6969
</nav>
7070
<div class="sidebar-footer">
71-
PerfSim .NET v1.0 • .NET 8/10
71+
Build: <span id="sidebarBuildTime">--</span>
7272
</div>
7373
</aside>
7474

@@ -307,8 +307,8 @@ <h2>📜 Event Log</h2>
307307
</main>
308308

309309
<footer class="footer">
310-
<p>Performance Problem Simulator - Educational Tool for Azure App Service Diagnostics</p>
311-
<p>Created by <a href="https://speckit.org/" target="_blank">SpecKit</a> in collaboration with <a href="mailto:rhamlett@microsoft.com">Richard Hamlett</a></p>
310+
<p>Performance Problem Simulator Educational Tool for Azure App Service Diagnostics</p>
311+
<p id="pageFooterContent"></p>
312312
<p>Build: <span id="buildTime">--</span></p>
313313
</footer>
314314

0 commit comments

Comments
 (0)