11using Immense . SimpleMessenger ;
22using Microsoft . AspNetCore . Authorization ;
33using Microsoft . AspNetCore . Components ;
4+ using Microsoft . Build . Framework ;
45using Microsoft . EntityFrameworkCore ;
6+ using Microsoft . Extensions . Logging ;
57using Remotely . Server . Enums ;
68using Remotely . Server . Hubs ;
79using 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 {
0 commit comments