Skip to content

Commit 08955cf

Browse files
authored
Merge pull request #725 from immense/bug/fix-device-filtering
Fix device filtering.
2 parents 428aa96 + 5f04782 commit 08955cf

File tree

3 files changed

+138
-104
lines changed

3 files changed

+138
-104
lines changed

Server/Components/Devices/DevicesFrame.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
</div>
8787
</div>
8888
<div id="deviceListDiv" class="p-2 mb-5">
89-
@foreach (var device in _devicesForPage)
89+
@foreach (var device in DisplayedDevices)
9090
{
9191
<CascadingValue Value="this">
9292
<DeviceCard @key="device.ID" Device="device" />

Server/Components/Devices/DevicesFrame.razor.cs

Lines changed: 137 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using Immense.SimpleMessenger;
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Components;
4+
using Microsoft.Build.Framework;
45
using Microsoft.EntityFrameworkCore;
6+
using Microsoft.Extensions.Logging;
57
using Remotely.Server.Enums;
68
using Remotely.Server.Hubs;
79
using Remotely.Server.Models.Messages;
@@ -29,44 +31,58 @@ public partial class DevicesFrame : AuthComponentBase
2931
private readonly string _deviceGroupAll = Guid.NewGuid().ToString();
3032
private readonly string _deviceGroupNone = Guid.NewGuid().ToString();
3133
private readonly List<DeviceGroup> _deviceGroups = new();
32-
private readonly List<Device> _devicesForPage = new();
3334
private readonly SemaphoreSlim _devicesLock = new(1,1);
3435
private readonly List<Device> _filteredDevices = new();
36+
private readonly List<Device> _prependedDevices = new();
3537
private readonly List<PropertyInfo> _sortableProperties = new();
3638
private int _currentPage = 1;
3739
private int _devicesPerPage = 25;
3840
private string? _filter;
3941
private bool _hideOfflineDevices = true;
42+
private string _lastFilterState = string.Empty;
4043
private string? _selectedGroupId;
4144
private string _selectedSortProperty = "DeviceName";
4245
private ListSortDirection _sortDirection;
4346

4447
[Inject]
4548
private ISelectedCardsStore CardStore { get; init; } = null!;
4649

47-
[Inject]
48-
private ITerminalStore TerminalStore { get; init; } = null!;
49-
5050
[Inject]
5151
private ICircuitConnection CircuitConnection { get; init; } = null!;
5252

53+
private string CurrentFilterState
54+
{
55+
get
56+
{
57+
return
58+
$"{_filter}" +
59+
$"{_selectedGroupId}|" +
60+
$"{_selectedSortProperty}|" +
61+
$"{_sortDirection}|" +
62+
$"{_hideOfflineDevices}|" +
63+
$"{_currentPage}|" +
64+
$"{_devicesPerPage}|";
65+
}
66+
}
5367
[Inject]
5468
private IDataService DataService { get; init; } = null!;
5569

70+
private Device[] DisplayedDevices => GetDisplayedDevices();
71+
72+
[Inject]
73+
private ILogger<DevicesFrame> Logger { get; init; } = null!;
74+
75+
[Inject]
76+
private ITerminalStore TerminalStore { get; init; } = null!;
77+
5678
[Inject]
5779
private IToastService ToastService { get; init; } = null!;
5880

5981
private int TotalPages => (int)Math.Max(1, Math.Ceiling((decimal)_filteredDevices.Count / _devicesPerPage));
6082

61-
private async Task HandleDisplayNotificationMessage(DisplayNotificationMessage message)
62-
{
63-
TerminalStore.AddTerminalLine(message.ConsoleText);
64-
ToastService.ShowToast(message.ToastText, classString: message.ClassName);
65-
await InvokeAsync(StateHasChanged);
66-
}
67-
6883
public async Task Refresh()
6984
{
85+
_lastFilterState = string.Empty;
7086
await LoadDevices();
7187
await InvokeAsync(StateHasChanged);
7288
}
@@ -104,42 +120,6 @@ await Register<ScriptResultMessage, string>(
104120
await LoadDevices();
105121
}
106122

107-
private async Task HandleScriptResultMessage(ScriptResultMessage message)
108-
{
109-
await AddScriptResult(message.ScriptResult);
110-
}
111-
112-
private async Task HandleDeviceStateChangedMessage(DeviceStateChangedMessage message)
113-
{
114-
await _devicesLock.WaitAsync();
115-
116-
try
117-
{
118-
var device = message.Device;
119-
120-
foreach (var collection in new[] { _allDevices, _devicesForPage })
121-
{
122-
var index = collection.FindIndex(x => x.ID == device.ID);
123-
if (index > -1)
124-
{
125-
collection[index] = device;
126-
}
127-
}
128-
129-
Debouncer.Debounce(TimeSpan.FromSeconds(2), Refresh);
130-
}
131-
finally
132-
{
133-
_devicesLock.Release();
134-
}
135-
}
136-
137-
protected override async Task OnAfterRenderAsync(bool firstRender)
138-
{
139-
await base.OnAfterRenderAsync(firstRender);
140-
await FilterDevices();
141-
}
142-
143123
private async Task AddScriptResult(ScriptResult result)
144124
{
145125
var deviceResult = await DataService.GetDevice(result.DeviceID);
@@ -167,88 +147,99 @@ private async Task AddScriptResult(ScriptResult result)
167147
private async Task ClearSelectedCard()
168148
{
169149
await Messenger.Send(
170-
new DeviceCardStateChangedMessage(string.Empty, DeviceCardState.Normal),
150+
new DeviceCardStateChangedMessage(string.Empty, DeviceCardState.Normal),
171151
CircuitConnection.ConnectionId);
172152
}
173153

174-
private async Task FilterDevices()
154+
private void FilterAndSortDevices()
175155
{
176-
await _devicesLock.WaitAsync();
177-
try
178-
{
179-
_filteredDevices.Clear();
180-
var appendDevices = new List<Device>();
156+
_filteredDevices.Clear();
157+
_prependedDevices.Clear();
181158

182-
foreach (var device in _allDevices)
159+
foreach (var device in _allDevices)
160+
{
161+
if (CardStore.SelectedDevices.Contains(device.ID))
183162
{
184-
if (CardStore.SelectedDevices.Contains(device.ID))
185-
{
186-
appendDevices.Add(device);
187-
}
163+
_prependedDevices.Add(device);
164+
}
188165

189-
if (!device.IsOnline && _hideOfflineDevices)
190-
{
191-
continue;
192-
}
166+
if (!device.IsOnline && _hideOfflineDevices)
167+
{
168+
continue;
169+
}
193170

194-
if (!string.IsNullOrWhiteSpace(_filter) &&
195-
device.Alias?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
196-
device.CurrentUser?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
197-
device.DeviceName?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
198-
device.Notes?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
199-
device.Platform?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
200-
device.Tags?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true)
201-
{
202-
continue;
203-
}
171+
if (!string.IsNullOrWhiteSpace(_filter) &&
172+
device.Alias?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
173+
device.CurrentUser?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
174+
device.DeviceName?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
175+
device.Notes?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
176+
device.Platform?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true &&
177+
device.Tags?.Contains(_filter, StringComparison.OrdinalIgnoreCase) != true)
178+
{
179+
continue;
180+
}
204181

205-
if (_selectedGroupId == _deviceGroupAll ||
206-
_selectedGroupId == device.DeviceGroupID ||
207-
(
208-
_selectedGroupId == _deviceGroupNone &&
209-
string.IsNullOrWhiteSpace(device.DeviceGroupID
210-
)))
211-
{
212-
_filteredDevices.Add(device);
213-
}
182+
if (_selectedGroupId == _deviceGroupAll ||
183+
_selectedGroupId == device.DeviceGroupID ||
184+
(
185+
_selectedGroupId == _deviceGroupNone &&
186+
string.IsNullOrWhiteSpace(device.DeviceGroupID
187+
)))
188+
{
189+
_filteredDevices.Add(device);
214190
}
191+
}
215192

216-
if (!string.IsNullOrWhiteSpace(_selectedSortProperty))
193+
if (!string.IsNullOrWhiteSpace(_selectedSortProperty))
194+
{
195+
var direction = _sortDirection == ListSortDirection.Ascending ? 1 : -1;
196+
_filteredDevices.Sort((a, b) =>
217197
{
218-
var direction = _sortDirection == ListSortDirection.Ascending ? 1 : -1;
219-
_filteredDevices.Sort((a, b) =>
198+
if (a.IsOnline != b.IsOnline)
220199
{
221-
if (a.IsOnline != b.IsOnline)
222-
{
223-
return b.IsOnline.CompareTo(a.IsOnline);
224-
}
200+
return b.IsOnline.CompareTo(a.IsOnline);
201+
}
225202

226-
var propInfo = _sortableProperties.Find(x => x.Name == _selectedSortProperty);
203+
var propInfo = _sortableProperties.Find(x => x.Name == _selectedSortProperty);
227204

228-
var valueA = propInfo?.GetValue(a);
229-
var valueB = propInfo?.GetValue(b);
205+
var valueA = propInfo?.GetValue(a);
206+
var valueB = propInfo?.GetValue(b);
230207

231-
return Comparer.Default.Compare(valueA, valueB) * direction;
232-
});
208+
return Comparer.Default.Compare(valueA, valueB) * direction;
209+
});
210+
}
211+
}
212+
213+
private Device[] GetDisplayedDevices()
214+
{
215+
_devicesLock.Wait();
216+
try
217+
{
218+
if (CurrentFilterState != _lastFilterState)
219+
{
220+
_lastFilterState = CurrentFilterState;
221+
FilterAndSortDevices();
233222
}
234223

235224
var skipCount = (_currentPage - 1) * _devicesPerPage;
236225
var devicesForPage = _filteredDevices
237-
.Except(appendDevices)
226+
.Except(_prependedDevices)
238227
.Skip(skipCount)
239228
.Take(_devicesPerPage);
240229

241-
_devicesForPage.Clear();
242-
_devicesForPage.AddRange(appendDevices.Concat(devicesForPage));
243-
230+
return _prependedDevices.Concat(devicesForPage).ToArray();
231+
}
232+
catch (Exception ex)
233+
{
234+
Logger.LogError(ex, "Error while filtering devices.");
235+
ToastService.ShowToast2("Filter devices failed", ToastType.Error);
236+
return Array.Empty<Device>();
244237
}
245238
finally
246239
{
247240
_devicesLock.Release();
248241
}
249242
}
250-
251-
252243
private string GetDisplayName(PropertyInfo propInfo)
253244
{
254245
return propInfo.GetCustomAttribute<DisplayAttribute>()?.Name ?? propInfo.Name;
@@ -259,12 +250,58 @@ private string GetSortIcon()
259250
return $"oi-sort-{_sortDirection.ToString().ToLower()}";
260251
}
261252

253+
private async Task HandleDeviceStateChangedMessage(DeviceStateChangedMessage message)
254+
{
255+
await _devicesLock.WaitAsync();
256+
257+
try
258+
{
259+
var device = message.Device;
260+
261+
var collections = new[] { _allDevices, _filteredDevices };
262+
263+
foreach (var collection in collections)
264+
{
265+
var index = collection.FindIndex(x => x.ID == device.ID);
266+
if (index > -1)
267+
{
268+
collection[index] = device;
269+
}
270+
else
271+
{
272+
collection.Add(device);
273+
}
274+
}
275+
276+
Debouncer.Debounce(
277+
TimeSpan.FromSeconds(2),
278+
async () =>
279+
{
280+
await InvokeAsync(StateHasChanged);
281+
});
282+
}
283+
finally
284+
{
285+
_devicesLock.Release();
286+
}
287+
}
288+
289+
private async Task HandleDisplayNotificationMessage(DisplayNotificationMessage message)
290+
{
291+
TerminalStore.AddTerminalLine(message.ConsoleText);
292+
ToastService.ShowToast(message.ToastText, classString: message.ClassName);
293+
await InvokeAsync(StateHasChanged);
294+
}
262295
private async Task HandleRefreshClicked()
263296
{
264297
await Refresh();
265298
ToastService.ShowToast("Devices refreshed.");
266299
}
267300

301+
private async Task HandleScriptResultMessage(ScriptResultMessage message)
302+
{
303+
await AddScriptResult(message.ScriptResult);
304+
}
268305
private async Task LoadDevices()
269306
{
270307
EnsureUserSet();
@@ -284,8 +321,6 @@ private async Task LoadDevices()
284321
{
285322
_devicesLock.Release();
286323
}
287-
288-
await FilterDevices();
289324
}
290325
private void PageDown()
291326
{

Shared/Entities/Device.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public class Device
5050
[Display(Name = "Last Online")]
5151
public DateTimeOffset LastOnline { get; set; }
5252

53-
[Sortable]
5453
[Display(Name = "MAC Addresses")]
5554
public string[] MacAddresses { get; set; } = Array.Empty<string>();
5655

0 commit comments

Comments
 (0)