Skip to content

Commit

Permalink
Fix/1242 filter devices by device model (#1511)
Browse files Browse the repository at this point in the history
* Filter devices by device model

* Modification test unitaire

* Test unitaire ok

Co-authored-by: crib <christophe.ribeiro@cgi.com>
  • Loading branch information
ChristopheRib63 and crib authored Nov 11, 2022
1 parent 040eefe commit 3e769e1
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 21 deletions.
82 changes: 80 additions & 2 deletions src/AzureIoTHub.Portal.Client/Pages/Devices/DeviceListPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
@inject PortalSettings Portal
@inject IDeviceTagSettingsClientService DeviceTagSettingsClientService
@inject IDeviceClientService DeviceClientService
@inject IDeviceModelsClientService DeviceModelsClientService

<MudGrid>
<MudItem xs="12">
<MudExpansionPanels>
<MudExpansionPanel Text="Search panel">
<MudGrid>
<MudItem xs="12" md="12">
<MudItem xs="12" md="6">
<MudTextField @bind-Value="searchID" Placeholder="DeviceID / DeviceName" id="searchID"></MudTextField>
</MudItem>
@foreach (DeviceTagDto tag in TagList)
Expand All @@ -27,6 +28,29 @@
</MudItem>
}
}
<MudItem xs="12" md="6">
<MudAutocomplete T="DeviceModelDto"
id="@nameof(DeviceModelDto.ModelId)"
@bind-Value="Model"
SearchFunc="@Search"
Label="Model"
Dense=true
For=@(() => this.Model)
Variant="Variant.Outlined"
ToStringFunc="@(x => x?.Name)"
ResetValueOnEmptyText=true
Immediate=true
Clearable=true
CoerceText=true
CoerceValue=false>
<ItemTemplate>
@context.Name
<MudText Typo="Typo.subtitle1" Class="mud-input-helper-text">
@((!string.IsNullOrEmpty(@context.Description) && @context.Description.Length > 100) ? @context.Description.Substring(0, 100) + "..." : @context.Description)
</MudText>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
<MudGrid>
<MudItem sm="12" md="6">
<MudText>Status</MudText>
Expand Down Expand Up @@ -168,11 +192,24 @@
private string searchID = "";
private string searchStatus;
private string searchState;

private MudTable<DeviceListItem> table;
private Dictionary<string, string> searchTags = new();

private bool IsLoading { get; set; } = true;

private List<DeviceModelDto> ModelList = new List<DeviceModelDto>();
private DeviceModelDto _model;

public DeviceModelDto Model
{
get => _model;
set
{
Task.Run(async () => await ChangeModel(value));
}
}

private IEnumerable<DeviceTagDto> TagList { get; set; } = new List<DeviceTagDto>();

private int[] pageSizeOptions = new int[] { 2, 5, 10 };
Expand All @@ -181,6 +218,7 @@
{
try
{
this.ModelList = (await DeviceModelsClientService.GetDeviceModels()).ToList();
// Gets the custom tags that can be searched via the panel
TagList = await DeviceTagSettingsClientService.GetDeviceTags();
foreach (var tag in TagList)
Expand Down Expand Up @@ -212,7 +250,7 @@
break;
}

var uri = $"api/devices?pageNumber={state.Page}&pageSize={state.PageSize}&searchText={HttpUtility.UrlEncode(searchID)}&searchStatus={searchStatus}&searchState={searchState}&orderBy={orderBy}";
var uri = $"api/devices?pageNumber={state.Page}&pageSize={state.PageSize}&searchText={HttpUtility.UrlEncode(searchID)}&searchStatus={searchStatus}&searchState={searchState}&orderBy={orderBy}&modelId={this.Model?.ModelId}";

foreach (var searchTag in searchTags.Where(c => !string.IsNullOrEmpty(c.Value)))
{
Expand Down Expand Up @@ -292,4 +330,44 @@
{
navigationManager.NavigateTo($"devices/{item.DeviceID}{((item.SupportLoRaFeatures && Portal.IsLoRaSupported) ? "?isLora=true" : "")}");
}

internal async Task ChangeModel(DeviceModelDto Model)
{
try
{
this._model = Model;

if (Model == null || string.IsNullOrWhiteSpace(Model.ModelId))
{
return;
}

}
catch (ProblemDetailsException exception)
{
Error?.ProcessProblemDetails(exception);
}
finally
{
await InvokeAsync(StateHasChanged);
}
}

/// <summary>
/// Allows to autocomplete the Device Model field in the form.
/// </summary>
/// <param name="value">Text entered in the field</param>
/// <returns>Item of the device model list that matches the user's value</returns>
public async Task<IEnumerable<DeviceModelDto>> Search(string value)
{
// In real life use an asynchronous function for fetching data from an api.
await Task.Delay(0);

// if text is null or empty, show complete list
if (string.IsNullOrEmpty(value))
return ModelList;

return ModelList
.Where(x => x.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,20 @@ public DevicesController(
/// <param name="searchStatus"></param>
/// <param name="searchState"></param>
/// <param name="pageSize"></param>
/// <param name="pageNumber"></param>
/// <param name="orderBy"></param>
/// <param name="modelId"></param>
[HttpGet(Name = "GET Device list")]
public Task<PaginationResult<DeviceListItem>> SearchItems(
string searchText = null,
bool? searchStatus = null,
bool? searchState = null,
int pageSize = 10,
int pageNumber = 0,
[FromQuery] string[] orderBy = null)
[FromQuery] string[] orderBy = null,
string modelId = null)
{
return GetItems("GET Device list", searchText, searchStatus, searchState, pageSize, pageNumber, orderBy);
return GetItems("GET Device list", searchText, searchStatus, searchState, pageSize, pageNumber, orderBy, modelId);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ protected DevicesControllerBase(
/// <param name="pageSize"></param>
/// <param name="pageNumber"></param>
/// <param name="orderBy"></param>
/// <param name="modelId"></param>
protected async Task<PaginationResult<DeviceListItem>> GetItems(
string routeName = null,
string searchText = null,
bool? searchStatus = null,
bool? searchState = null,
int pageSize = 10,
int pageNumber = 0,
string[] orderBy = null)
string[] orderBy = null,
string modelId = null)
{

var paginatedDevices = await this.deviceService.GetDevices(
Expand All @@ -58,7 +60,8 @@ protected async Task<PaginationResult<DeviceListItem>> GetItems(
pageSize,
pageNumber,
orderBy,
GetTagsFromQueryString(Request.Query));
GetTagsFromQueryString(Request.Query),
modelId);

var nextPage = string.Empty;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,18 @@ public LoRaWANDevicesController(
/// <param name="pageSize"></param>
/// <param name="pageNumber"></param>
/// <param name="orderBy"></param>
/// <param name="modelId"></param>
[HttpGet(Name = "GET LoRaWAN device list")]
public Task<PaginationResult<DeviceListItem>> SearchItems(
string searchText = null,
bool? searchStatus = null,
bool? searchState = null,
int pageSize = 10,
int pageNumber = 0,
[FromQuery] string[] orderBy = null)
[FromQuery] string[] orderBy = null,
string modelId = null)
{
return GetItems("GET LoRaWAN device list", searchText, searchStatus, searchState, pageSize, pageNumber, orderBy);
return GetItems("GET LoRaWAN device list", searchText, searchStatus, searchState, pageSize, pageNumber, orderBy, modelId);
}

/// <summary>
Expand Down
11 changes: 9 additions & 2 deletions src/AzureIoTHub.Portal.Server/Services/DeviceServiceBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected DeviceServiceBase(PortalDbContext portalDbContext,
}

public async Task<PaginatedResult<DeviceListItem>> GetDevices(string searchText = null, bool? searchStatus = null, bool? searchState = null, int pageSize = 10,
int pageNumber = 0, string[] orderBy = null, Dictionary<string, string> tags = default)
int pageNumber = 0, string[] orderBy = null, Dictionary<string, string> tags = default, string modelId = null)
{
var deviceListFilter = new DeviceListFilter
{
Expand All @@ -53,7 +53,8 @@ public async Task<PaginatedResult<DeviceListItem>> GetDevices(string searchText
IsEnabled = searchStatus,
Keyword = searchText,
OrderBy = orderBy,
Tags = GetSearchableTags(tags)
Tags = GetSearchableTags(tags),
ModelId = modelId
};

var devicePredicate = PredicateBuilder.True<Device>();
Expand Down Expand Up @@ -86,6 +87,12 @@ public async Task<PaginatedResult<DeviceListItem>> GetDevices(string searchText
value.Name.Equals(keyValuePair.Key) && value.Value.Equals(keyValuePair.Value)));
}

if (!string.IsNullOrWhiteSpace(deviceListFilter.ModelId))
{
devicePredicate = devicePredicate.And(device => device.DeviceModelId.Equals(deviceListFilter.ModelId));
lorawanDevicePredicate = lorawanDevicePredicate.And(device => device.DeviceModelId.Equals(deviceListFilter.ModelId));
}

var query = this.portalDbContext.Devices
.Include(device => device.Tags)
.Where(devicePredicate)
Expand Down
3 changes: 2 additions & 1 deletion src/AzureIoTHub.Portal.Server/Services/IDeviceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ Task<PaginatedResult<DeviceListItem>> GetDevices(
int pageSize = 10,
int pageNumber = 0,
string[] orderBy = null,
Dictionary<string, string> tags = default);
Dictionary<string, string> tags = default,
string modelId = null);

Task<TDto> GetDevice(string deviceId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public class DeviceListFilter : PaginationFilter
public bool? IsConnected { get; set; }

public Dictionary<string, string> Tags { get; set; }

public string ModelId { get; set; }
}
}
Loading

0 comments on commit 3e769e1

Please sign in to comment.