Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,14 @@ The following were implemented in the WiFi Optimizer feature:
- Easy deployment to customer sites without Docker expertise
- Consider: Ubuntu Server base, auto-updates, web-based initial setup

## UI / Tooltips

### Audit Clickable Tooltips for `data-tooltip-hover-only`
- `data-tooltip-hover-only` is the unified attribute for clickable elements - sets `trigger: 'mouseenter'` and `touch: false` so tapping on mobile just performs the action
- Buttons (`<button>`) get this behavior automatically via tag detection in App.razor
- Non-button clickables (`<a>`, `<div>` with `@onclick`, etc.) need the explicit `data-tooltip-hover-only` attribute
- Audit remaining clickable elements across the app and add the attribute where missing

## General

### 3D Map - Speed Test Path Overlay Rework
Expand Down
10 changes: 0 additions & 10 deletions src/NetworkOptimizer.Web/App.razor
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,6 @@
}
if (el.hasAttribute('data-tooltip-hover-only') || el.tagName === 'BUTTON') {
opts.trigger = 'mouseenter';
}
// Desktop-hover only: no click trigger and no tap on touch devices,
// so the tap just performs the element's action.
if (el.hasAttribute('data-tooltip-no-touch')) {
opts.trigger = 'mouseenter';
opts.touch = false;
}
tippy(el, opts);
Expand Down Expand Up @@ -299,11 +294,6 @@
}
if (el.hasAttribute('data-tooltip-hover-only') || el.tagName === 'BUTTON') {
opts.trigger = 'mouseenter';
}
// Desktop-hover only: no click trigger and no tap on touch devices,
// so the tap just performs the element's action.
if (el.hasAttribute('data-tooltip-no-touch')) {
opts.trigger = 'mouseenter';
opts.touch = false;
}
if (el._tippy) {
Expand Down
2 changes: 1 addition & 1 deletion src/NetworkOptimizer.Web/Components/Pages/Monitoring.razor
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ else
<div class="stat-label">WAN Upload</div>
</div>
@{ var ispHealth = IspHealthService.GetCachedScore(); }
<div class="monitoring-stat-card clickable-stat-card isp-health-tile @ispHealth.TileCssClass" data-tooltip="@ispHealth.TileTooltip" data-tooltip-no-touch @onclick="@(() => NavigationManager.NavigateTo("/monitoring?tab=isp-health"))">
<div class="monitoring-stat-card clickable-stat-card isp-health-tile @ispHealth.TileCssClass" data-tooltip="@ispHealth.TileTooltip" data-tooltip-hover-only @onclick="@(() => NavigationManager.NavigateTo("/monitoring?tab=isp-health"))">
<div class="stat-value isp-tile-score">@ispHealth.TileText</div>
<div class="stat-label">ISP Health</div>
@if (ispHealth.Status == IspHealthStatus.Ready && ispHealth.Score.HasValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ else
<div class="stat-label">WAN Upload</div>
</div>
@{ var ispHealth = IspHealthService.GetCachedScore(); }
<div class="monitoring-stat-card clickable-stat-card isp-health-tile @ispHealth.TileCssClass" data-tooltip="@ispHealth.TileTooltip" data-tooltip-no-touch @onclick="@(() => NavigationManager.NavigateTo("/monitoring?tab=isp-health"))">
<div class="monitoring-stat-card clickable-stat-card isp-health-tile @ispHealth.TileCssClass" data-tooltip="@ispHealth.TileTooltip" data-tooltip-hover-only @onclick="@(() => NavigationManager.NavigateTo("/monitoring?tab=isp-health"))">
<div class="stat-value isp-tile-score">@ispHealth.TileText</div>
<div class="stat-label">ISP Health</div>
@if (ispHealth.Status == IspHealthStatus.Ready && ispHealth.Score.HasValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ else
var r = _report;
<div class="isp-health-toolbar">
<button class="btn btn-sm btn-secondary" @onclick="RefreshAsync" disabled="@_refreshing"
data-tooltip="Recompute ISP Health now from the latest monitoring data" data-tooltip-no-touch>
data-tooltip="Recompute ISP Health now from the latest monitoring data" data-tooltip-hover-only>
@if (_refreshing)
{
<span class="spinner-sm"></span> <span>Refreshing</span>
Expand Down
18 changes: 15 additions & 3 deletions src/NetworkOptimizer.Web/Services/SponsorshipService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NetworkOptimizer.Storage.Interfaces;
using NetworkOptimizer.Storage.Models;

Expand All @@ -14,6 +13,8 @@ public class SponsorshipService : ISponsorshipService
private const string GitHubSponsorUrl = "https://github.com/sponsors/tvancott42";
private const string KofiUrl = "https://ko-fi.com/tjtuna42";
private const int SqmEnabledBonus = 3;
private const int MonitoringEnabledBonus = 3;
private const int MonitoringTargetsDivisor = 5;

private readonly IServiceProvider _serviceProvider;
private readonly ILogger<SponsorshipService> _logger;
Expand Down Expand Up @@ -177,22 +178,25 @@ private async Task<int> GetUsageCountInternalAsync(IServiceScope scope)
var sqmWan1Task = speedTestRepository.GetSqmWanConfigAsync(1);
var sqmWan2Task = speedTestRepository.GetSqmWanConfigAsync(2);

// Floor plan feature counts and perf tweaks via DbContext
// Floor plan feature counts, perf tweaks, and monitoring via DbContext
Task<int> signalLogCountTask;
Task<int> placedApCountTask;
Task<int> plannedApCountTask;
Task<int> floorCountTask;
Task<int> perfTweakCountTask;
Task<int> monitoringTargetCountTask;
using (var db = await dbFactory.CreateDbContextAsync())
{
signalLogCountTask = db.ClientSignalLogs.CountAsync();
placedApCountTask = db.ApLocations.CountAsync();
plannedApCountTask = db.PlannedAps.CountAsync();
floorCountTask = db.FloorPlans.CountAsync();
perfTweakCountTask = db.PerfTweakSettings.CountAsync();
monitoringTargetCountTask = db.MonitoringTargets.Where(t => t.Enabled).CountAsync();

await Task.WhenAll(manualAuditCountTask, scheduledAuditCountTask, speedTestCountTask, sqmWan1Task, sqmWan2Task,
signalLogCountTask, placedApCountTask, plannedApCountTask, floorCountTask, perfTweakCountTask);
signalLogCountTask, placedApCountTask, plannedApCountTask, floorCountTask, perfTweakCountTask,
monitoringTargetCountTask);
}

// Manual audits count as 1, scheduled audits count as 0.2 (~2 per workweek), speed tests count as 0.5
Expand All @@ -217,6 +221,14 @@ await Task.WhenAll(manualAuditCountTask, scheduledAuditCountTask, speedTestCount
// 2 points per deployed performance tweak
count += perfTweakCountTask.Result * 2;

// Monitoring: flat bonus if InfluxDB is connected, plus 1 per 5 enabled targets
var influxClient = scope.ServiceProvider.GetRequiredService<MonitoringInfluxClient>();
if (influxClient.IsConfigured)
{
count += MonitoringEnabledBonus;
}
count += monitoringTargetCountTask.Result / MonitoringTargetsDivisor;

return count;
}

Expand Down
Loading