|
4 | 4 | @using Quartz |
5 | 5 | @using Humanizer |
6 | 6 | @using NBitcoin |
| 7 | +@using Blazorise.Components |
7 | 8 | @using NodeGuard.Jobs |
8 | 9 | @using Google.Protobuf |
9 | 10 | @using NBXplorer.Models |
|
287 | 288 | </Tooltip> |
288 | 289 | </h3> |
289 | 290 | <br/> |
| 291 | +<Row Class="mb-3" @key="_filtersResetKey"> |
| 292 | + <Column ColumnSize="ColumnSize.Is1"> |
| 293 | + <Field> |
| 294 | + <FieldLabel>Status</FieldLabel> |
| 295 | + <Autocomplete TItem="ChannelOperationRequestStatus?" |
| 296 | + TValue="ChannelOperationRequestStatus?" |
| 297 | + Data="@_statusOptions" |
| 298 | + TextField="@(item => item?.Humanize() ?? "All")" |
| 299 | + ValueField="@(item => item)" |
| 300 | + @bind-SelectedValue="@_statusFilter" |
| 301 | + @bind-SelectedValue:after="OnFiltersChanged" |
| 302 | + Placeholder="All" |
| 303 | + FreeTyping="false" |
| 304 | + MinLength="0" |
| 305 | + Filter="AutocompleteFilter.Contains" /> |
| 306 | + </Field> |
| 307 | + </Column> |
| 308 | + <Column ColumnSize="ColumnSize.Is1"> |
| 309 | + <Field> |
| 310 | + <FieldLabel>Type</FieldLabel> |
| 311 | + <Autocomplete TItem="OperationRequestType?" |
| 312 | + TValue="OperationRequestType?" |
| 313 | + Data="@_requestTypeOptions" |
| 314 | + TextField="@(item => item?.Humanize() ?? "All")" |
| 315 | + ValueField="@(item => item)" |
| 316 | + @bind-SelectedValue="@_requestTypeFilter" |
| 317 | + @bind-SelectedValue:after="OnFiltersChanged" |
| 318 | + Placeholder="All" |
| 319 | + FreeTyping="false" |
| 320 | + MinLength="0" |
| 321 | + Filter="AutocompleteFilter.Contains" /> |
| 322 | + </Field> |
| 323 | + </Column> |
| 324 | + <Column ColumnSize="ColumnSize.Is2"> |
| 325 | + <Field> |
| 326 | + <FieldLabel>Source Node</FieldLabel> |
| 327 | + <Autocomplete TItem="Node" |
| 328 | + TValue="int?" |
| 329 | + Data="@_availableNodes" |
| 330 | + TextField="@(item => item?.Name ?? "All")" |
| 331 | + ValueField="@(item => (int?)item?.Id)" |
| 332 | + @bind-SelectedValue="@_sourceNodeFilter" |
| 333 | + @bind-SelectedValue:after="OnFiltersChanged" |
| 334 | + Placeholder="All" |
| 335 | + FreeTyping="false" |
| 336 | + MinLength="0" |
| 337 | + Filter="AutocompleteFilter.Contains" /> |
| 338 | + </Field> |
| 339 | + </Column> |
| 340 | + <Column ColumnSize="ColumnSize.Is2"> |
| 341 | + <Field> |
| 342 | + <FieldLabel>Dest Node</FieldLabel> |
| 343 | + <Autocomplete TItem="Node" |
| 344 | + TValue="int?" |
| 345 | + Data="@_availableNodes" |
| 346 | + TextField="@(item => item?.Name ?? "All")" |
| 347 | + ValueField="@(item => (int?)item?.Id)" |
| 348 | + @bind-SelectedValue="@_destNodeFilter" |
| 349 | + @bind-SelectedValue:after="OnFiltersChanged" |
| 350 | + Placeholder="All" |
| 351 | + FreeTyping="false" |
| 352 | + MinLength="0" |
| 353 | + Filter="AutocompleteFilter.Contains" /> |
| 354 | + </Field> |
| 355 | + </Column> |
| 356 | + <Column ColumnSize="ColumnSize.Is2"> |
| 357 | + <Field> |
| 358 | + <FieldLabel>Wallet</FieldLabel> |
| 359 | + <Autocomplete TItem="Wallet" |
| 360 | + TValue="int?" |
| 361 | + Data="@_allWallets" |
| 362 | + TextField="@(item => item?.Name ?? "All")" |
| 363 | + ValueField="@(item => (int?)item?.Id)" |
| 364 | + @bind-SelectedValue="@_walletFilter" |
| 365 | + @bind-SelectedValue:after="OnFiltersChanged" |
| 366 | + Placeholder="All" |
| 367 | + FreeTyping="false" |
| 368 | + MinLength="0" |
| 369 | + Filter="AutocompleteFilter.Contains" /> |
| 370 | + </Field> |
| 371 | + </Column> |
| 372 | + <Column ColumnSize="ColumnSize.Is1"> |
| 373 | + <Field> |
| 374 | + <FieldLabel>User</FieldLabel> |
| 375 | + <Autocomplete TItem="ApplicationUser" |
| 376 | + TValue="string?" |
| 377 | + Data="@_availableUsers" |
| 378 | + TextField="@(item => item?.UserName ?? "All")" |
| 379 | + ValueField="@(item => item?.Id)" |
| 380 | + @bind-SelectedValue="@_userFilter" |
| 381 | + @bind-SelectedValue:after="OnFiltersChanged" |
| 382 | + Placeholder="All" |
| 383 | + FreeTyping="false" |
| 384 | + MinLength="0" |
| 385 | + Filter="AutocompleteFilter.Contains" /> |
| 386 | + </Field> |
| 387 | + </Column> |
| 388 | + <Column ColumnSize="ColumnSize.Is1"> |
| 389 | + <Field> |
| 390 | + <FieldLabel>From</FieldLabel> |
| 391 | + <DatePicker TValue="DateTime?" @bind-Date="@_fromDate" @bind-Date:after="OnFiltersChanged" InputMode="DateInputMode.Date" Placeholder="Start" /> |
| 392 | + </Field> |
| 393 | + </Column> |
| 394 | + <Column ColumnSize="ColumnSize.Is1"> |
| 395 | + <Field> |
| 396 | + <FieldLabel>To</FieldLabel> |
| 397 | + <DatePicker TValue="DateTime?" @bind-Date="@_toDate" @bind-Date:after="OnFiltersChanged" InputMode="DateInputMode.Date" Placeholder="End" /> |
| 398 | + </Field> |
| 399 | + </Column> |
| 400 | + <Column ColumnSize="ColumnSize.Is1" Class="d-flex align-items-end pb-3"> |
| 401 | + <Button Color="Color.Secondary" Clicked="ClearAllFilters"> |
| 402 | + <Icon Name="IconName.Times" /> Clear |
| 403 | + </Button> |
| 404 | + </Column> |
| 405 | +</Row> |
| 406 | +@* TODO: Convert this grid to paginated ReadData to avoid loading all records in memory. *@ |
290 | 407 | <DataGrid TItem="ChannelOperationRequest" |
291 | 408 | @ref="@_allRequestsDatagrid" |
292 | 409 | Data="@_allRequests" |
293 | | - Filterable="true" |
| 410 | + ReadData="@OnAllRequestsReadData" |
| 411 | + TotalItems="@_totalAllRequests" |
294 | 412 | ShowPager="true" |
295 | 413 | ShowPageSizes="true" |
296 | 414 | Striped="true"> |
|
455 | 573 | @inject IPriceConversionService PriceConversionService |
456 | 574 | @inject IAuditService AuditService |
457 | 575 | @inject IHttpContextAccessor HttpContextAccessor |
| 576 | +@inject IApplicationUserRepository ApplicationUserRepository |
458 | 577 |
|
459 | 578 | @code { |
460 | 579 | private List<ChannelOperationRequest>? _channelRequests; |
461 | 580 | private List<ChannelOperationRequest>? _allRequests; |
| 581 | + private int _totalAllRequests; |
| 582 | + private List<ApplicationUser> _availableUsers = new(); |
| 583 | + private List<Node> _availableNodes = new(); |
| 584 | + |
| 585 | + // Filter state |
| 586 | + private ChannelOperationRequestStatus? _statusFilter; |
| 587 | + private OperationRequestType? _requestTypeFilter; |
| 588 | + private int? _sourceNodeFilter; |
| 589 | + private int? _destNodeFilter; |
| 590 | + private int? _walletFilter; |
| 591 | + private string? _userFilter; |
| 592 | + private int _filtersResetKey; |
| 593 | + private DateTime? _fromDate; |
| 594 | + private DateTime? _toDate; |
| 595 | + |
| 596 | + // Filter options |
| 597 | + private List<ChannelOperationRequestStatus?> _statusOptions = new() { null }; |
| 598 | + private List<OperationRequestType?> _requestTypeOptions = new() { null }; |
| 599 | + |
462 | 600 | private ChannelOperationRequest? _selectedRequest; |
463 | 601 | private ChannelOperationRequestStatus _selectedStatus; |
464 | 602 | private ChannelOperationRequest _selectedRequestForMarkingAsFailed; |
|
1136 | 1274 | private async Task RefreshChannelRequestsInformation() |
1137 | 1275 | { |
1138 | 1276 | await FetchRequests(); |
| 1277 | + if (_allRequestsDatagrid != null) |
| 1278 | + { |
| 1279 | + await _allRequestsDatagrid.Reload(); |
| 1280 | + } |
1139 | 1281 | StateHasChanged(); |
1140 | 1282 | } |
| 1283 | + |
| 1284 | + private async Task OnAllRequestsReadData(DataGridReadDataEventArgs<ChannelOperationRequest> e) |
| 1285 | + { |
| 1286 | + if (!e.CancellationToken.IsCancellationRequested) |
| 1287 | + { |
| 1288 | + var fromDateOffset = _fromDate.HasValue ? new DateTimeOffset(_fromDate.Value, TimeSpan.Zero) : (DateTimeOffset?)null; |
| 1289 | + var toDateOffset = _toDate.HasValue ? new DateTimeOffset(_toDate.Value.AddDays(1).AddSeconds(-1), TimeSpan.Zero) : (DateTimeOffset?)null; |
| 1290 | + |
| 1291 | + var excludedIds = _channelRequests?.Select(r => r.Id) ?? Enumerable.Empty<int>(); |
| 1292 | + |
| 1293 | + var (requests, totalCount) = await ChannelOperationRequestRepository.GetPaginatedAsync( |
| 1294 | + e.Page, |
| 1295 | + e.PageSize, |
| 1296 | + _statusFilter, |
| 1297 | + _requestTypeFilter, |
| 1298 | + _sourceNodeFilter, |
| 1299 | + _destNodeFilter, |
| 1300 | + _walletFilter, |
| 1301 | + _userFilter, |
| 1302 | + fromDateOffset, |
| 1303 | + toDateOffset, |
| 1304 | + excludedIds); |
| 1305 | + |
| 1306 | + _allRequests = requests; |
| 1307 | + _totalAllRequests = totalCount; |
| 1308 | + } |
| 1309 | + } |
| 1310 | + |
| 1311 | + private async Task OnFiltersChanged() |
| 1312 | + { |
| 1313 | + if (_allRequestsDatagrid != null) |
| 1314 | + { |
| 1315 | + await _allRequestsDatagrid.Reload(); |
| 1316 | + } |
| 1317 | + } |
| 1318 | + |
| 1319 | + private async Task ClearAllFilters() |
| 1320 | + { |
| 1321 | + _statusFilter = null; |
| 1322 | + _requestTypeFilter = null; |
| 1323 | + _sourceNodeFilter = null; |
| 1324 | + _destNodeFilter = null; |
| 1325 | + _walletFilter = null; |
| 1326 | + _userFilter = null; |
| 1327 | + _fromDate = null; |
| 1328 | + _toDate = null; |
| 1329 | + _filtersResetKey++; |
| 1330 | + |
| 1331 | + if (_allRequestsDatagrid != null) |
| 1332 | + { |
| 1333 | + await _allRequestsDatagrid.Reload(); |
| 1334 | + } |
| 1335 | + } |
1141 | 1336 |
|
1142 | 1337 | private async Task OnChangelessChanged(bool value) |
1143 | 1338 | { |
|
0 commit comments